在ASP.NET Core web应用程序的控制器中,我希望刷新存储在客户端上的cookie票证中的用户和声明。
客户端已通过身份验证和授权,ASP.NET Core Identity将此信息存储在cookie票证中——现在,在某些控制器操作中,我希望刷新cookie中的数据。
SignInManager
具有刷新RefreshSignInAsync
的功能,但不接受HttpContext.User
作为参数。
[HttpPost("[action]")]
[Authorize]
public async Task<IActionResult> Validate()
{
// todo: update the Client Cookie
await _signInManager.RefreshSignInAsync(User); // wrong type
}
如何刷新cookie?
public static class HttpContextExtensions
{
public static async Task RefreshLoginAsync(this HttpContext context)
{
if (context.User == null)
return;
// The example uses base class, IdentityUser, yours may be called
// ApplicationUser if you have added any extra fields to the model
var userManager = context.RequestServices
.GetRequiredService<UserManager<IdentityUser>>();
var signInManager = context.RequestServices
.GetRequiredService<SignInManager<IdentityUser>>();
IdentityUser user = await userManager.GetUserAsync(context.User);
if(signInManager.IsSignedIn(context.User))
{
await signInManager.RefreshSignInAsync(user);
}
}
}
然后在你的控制器中使用它
[HttpPost("[action]")]
[Authorize]
public async Task<IActionResult> Validate()
{
await HttpContext.RefreshLoginAsync();
}
或者在动作过滤器中提取
public class RefreshLoginAttribute : ActionFilterAttribute
{
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
await context.HttpContext.RefreshLoginAsync();
await next();
}
}
然后在你的控制器中像这样使用它
[HttpPost("[action]")]
[Authorize]
[RefreshLogin] // or simpler [Authorize, RefreshLogin]
public async Task<IActionResult> Validate()
{
// your normal controller code
}
如果用户已经注销(他们的访问令牌已过期,但刷新令牌仍然有效),也可能发生这种情况。
重要提示:以下仅适用于您有"是否要记住用户的设备"设置为";否";在cognito配置中。如果有人知道如何使用它,请告诉我
我们使用以下流程(js客户端应用程序连接到.NET Core API):
- 用户使用用户名/密码登录(
CognitoSignInManager<CognitoUser>.PasswordSignInAsync
) - 客户端接收
token
、userID
和refreshToken
,并将它们存储在localStorage中 - 当原始令牌过期(1小时)时,客户端从API获得401错误
- 客户端使用
userID
和refreshToken
调用另一个API端点,然后后者在我们的用户服务上调用下面的代码 - 如果刷新结果成功,我们将返回新的令牌(
AuthenticationResult.IdToken
) - 客户端使用新令牌重复401中最初出错的调用
这是我们添加到用户服务的代码:
public async Task<UserLoginResult> SignInRefreshAsync(string uid, string refreshToken)
{
try
{
var result = await _cognitoIdentityProvider.InitiateAuthAsync(
new InitiateAuthRequest
{
AuthFlow = AuthFlowType.REFRESH_TOKEN_AUTH,
ClientId = _pool.ClientID,
AuthParameters = new Dictionary<string, string>
{
{ "REFRESH_TOKEN", refreshToken },
{ "SECRET_HASH", HmacSHA256(uid + _pool.ClientID, _options.UserPoolClientSecret) }
}
});
if (!result.HttpStatusCode.Successful() || string.IsNullOrEmpty(result.AuthenticationResult?.IdToken))
return new UserLoginResult(UserLoginStatus.Failed);
return new UserLoginResult(UserLoginStatus.Success, uid, null, null, result.AuthenticationResult.IdToken, null);
}
catch
{
return new UserLoginResult(UserLoginStatus.Failed);
}
}
private static string HmacSHA256(string data, string key)
{
using (var sha = new System.Security.Cryptography.HMACSHA256(System.Text.Encoding.UTF8.GetBytes(key)))
{
var result = sha.ComputeHash(System.Text.Encoding.UTF8.GetBytes(data));
return Convert.ToBase64String(result);
}
}
从DI中解析CCD_ 11。
CCD_ 12和CCD_。
UserLoginResult
是我们用来保存令牌和刷新令牌的类。显然,要进行相应的调整。
请注意,根据您的配置是Cognito,可能不需要设置SECRET_HASH
。