刷新ASP.Net核心标识中的用户cookie票证

时间:2017-01-26 09:26:48

标签: c# asp.net-core asp.net-identity

在ASP.NET Core Web应用程序的控制器中,我想刷新存储在客户端上的cookie票证中的用户和声明。

客户端经过身份验证和授权,ASP.NET Core Identity将此信息存储在cookie票证中 - 现在在某些Controller操作中我想刷新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?

2 个答案:

答案 0 :(得分:12)

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
}

答案 1 :(得分:0)

如果用户已已注销(其访问令牌已过期,但其刷新令牌仍然有效),这也是可能的。

重要说明:仅当您具有“是否要记住用户的设备?”时,以下内容才有效。在Cognito配置中设置为“否”。如果有人知道如何使用它,请告诉我。

我们使用以下流程(连接到.NET Core API的js客户端应用程序):

  1. 用户使用用户名/密码(CognitoSignInManager<CognitoUser>.PasswordSignInAsync)登录
  2. 客户端收到tokenuserIDrefreshToken并将其存储在localStorage中。
  3. 原始令牌过期(1小时)后,客户端会从API收到401错误。
  4. 客户端使用userIDrefreshToken调用另一个API端点,然后依次在我们的用户服务上调用以下代码。
  5. 如果刷新结果成功,我们将返回新令牌(AuthenticationResult.IdToken)。
  6. 客户端通过新令牌重复最初在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);
    }
}

IAmazonCognitoIdentityProvider _cognitoIdentityProvider通过DI解析。

AWSCognitoClientOptions _options = configuration.GetAWSCognitoClientOptions();IConfiguration configuration也可以通过DI解析。

UserLoginResult是我们的类,用于保存令牌和刷新令牌。显然,进行相应的调整。

请注意,根据您的配置为Cognito,可能不需要设置SECRET_HASH