Update user claims on site if claims changed on my identity server's database

huangapple go评论131阅读模式
英文:

Update user claims on site if claims changed on my identity server's database

问题

我有几个需要特定权限的站点,比如角色、组,所以我决定创建自己的身份服务器,使用用户数据库。我使用了JWT令牌和Cookie身份验证来实现我的目标。当未登录的用户尝试访问我的任何站点时,站点将重定向到身份服务器的登录页面。登录成功后,服务器生成带有用户声明的JWT令牌,

private async Task<string> CreateAccessToken(User user)
{
    // 代码已翻译
}

该令牌将被提取并存储在客户端计算机上的cookie文件中,以便与站点资源一起使用。

public async Task<IActionResult> TokenForCookie(string token)
{
    // 代码已翻译
}

这对我来说很好,但唯一的问题是:如何在身份服务器的管理员更改它们或在数据库中手动更改它们时更新用户声明?

我查阅了一些文章,似乎我需要创建一些验证器,添加到每个请求中,以比较资源站点和身份服务器之间的声明。我是asp.net core和身份流程的新手,所以我花了一周多时间构建至少类似于这样的东西。如果你知道更好的方法来完成这项工作,请帮助我找到正确的方法。

英文:

I have a couple of sites that require a logged user with specific permissions like role, group. So i decided to create my own identity server with the user's database. I used JWt-token and cookie auth to achieve my goal. When a not-logged-in user tries to get access to any of my sites, the site redirects him to the identity server's login page. After successful login, the server generates JWT token with the user's claims

private async Task&lt;string&gt; CreateAccessToken(User user)
        {
            var claims = new List&lt;Claim&gt;
                {
                    new Claim(ClaimTypes.Name, user.UserName),
                    new Claim(ClaimTypes.Email, user.Email)
            };

            var userRoles = await _userManager.GetRolesAsync(user);

            foreach (var userRole in userRoles)
            {
                claims.Add(new Claim(ClaimTypes.Role, userRole));
                var role = await _roleManager.FindByNameAsync(userRole);
                if (role != null)
                {
                    var roleClaims = await _roleManager.GetClaimsAsync(role);
                    foreach (Claim roleClaim in roleClaims)
                    {
                        claims.Add(roleClaim);
                    }
                }
            }

            var jwt = new JwtSecurityToken(
                    issuer: AuthOptions.ISSUER,
                    audience: AuthOptions.AUDIENCE,
                    claims: claims,
                    expires: DateTime.UtcNow.Add(TimeSpan.FromMinutes(4)),
                    signingCredentials: new SigningCredentials(AuthOptions.GetSymmetricSecurityKey(), SecurityAlgorithms.HmacSha256));
            var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

            return encodedJwt;

        }

which will be extracted and stored in the cookie file on client PC to work with site's resources.

public async Task&lt;IActionResult&gt; TokenForCookie(string token)
        {
            HttpContext.Session.SetString(&quot;accesstoken&quot;, token);
            var JWThandler = new JwtSecurityTokenHandler();
            var validations = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer = AuthOptions.ISSUER,
                ValidateAudience = true,
                ValidAudience = AuthOptions.AUDIENCE,
                ValidateLifetime = true,
                IssuerSigningKey = AuthOptions.GetSymmetricSecurityKey(),
                ValidateIssuerSigningKey = true
            };

            SecurityToken tokenSecure;
            ClaimsPrincipal claimsPrincipal;

            try
            {
                claimsPrincipal = JWThandler.ValidateToken(token, validations, out tokenSecure);
            }
            catch (Exception ex)
            {
                HttpContext.Response.StatusCode = 500;
                return new JsonResult(new { success = false, message = &quot;Token validation error&quot; });
            }

            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal,
    new AuthenticationProperties
    {
        IsPersistent = true,
        AllowRefresh = true
    });

            return RedirectToPage(&quot;/Index&quot;);
        }

This works fine for me, but the only problem is: how can i update user's claims if the identity server's admins changed them or if they changed manually in the database?

I googled some articles and seems like i need to create some validator added to each request for comparing claims between resources sites and identity server. I am new to the asp.net core and identity process so i spent more than a week building at least something like that. If you know a better way how this can be done, please help me to find the right way

答案1

得分: 0

这是有关API场景的通用解决方案,即刷新令牌。
当用户登录时,他会获取访问令牌和刷新令牌。
访问令牌与用户权限在较短时间内过期,如1天。这可以防止旧的权限(角色)继续有效。当访问令牌过期时,您可以只使用刷新令牌获取新的访问令牌,因此无需重新登录以获取访问令牌,刷新令牌会为您进行身份验证。

刷新令牌的过期时间较长,如数月,但它不包含任何用户权限(角色)的信息。它仅用于获取包含用户权限(角色)的新访问令牌。刷新令牌只是简单地生成,它只是一个随机代码:

private static string GenerateRefreshToken()
{
    var randomNumber = new byte[64];
    using var rng = RandomNumberGenerator.Create();
    rng.GetBytes(randomNumber);
    return Convert.ToBase64String(randomNumber);
}

关于刷新令牌的工作原理,您可以尝试使用此带有可下载代码的教程:https://www.c-sharpcorner.com/article/jwt-authentication-with-refresh-tokens-in-net-6-0/

您的项目使用了cookie,因此您应该使cookie更快地过期。然后,使用刷新令牌通过每个请求获取访问令牌,或使用JavaScript定时器在后台每天进行此请求以进行更新。

英文:

There is general solution for api scenario, which is refresh token.<br>
When user login, he get access token & refresh token. <br>

The access token with user principals exipred in a shorter time such as 1 day. This prevents the old principals(roles) keeps being effective. When access token expired, you can get a new access token just using the refresh token. thus you don't have to login again to get access token, the refresh token authenticate for you.

refresh token has longer expire time such as months, but it doesn't contain any information of user principals(roles). It is just used for getting new access token which contains user principals(roles).
Refresh token is simply generated , just a random code:

        private static string GenerateRefreshToken()
        {
            var randomNumber = new byte[64];
            using var rng = RandomNumberGenerator.Create();
            rng.GetBytes(randomNumber);
            return Convert.ToBase64String(randomNumber);
        }

For how refresh token work,you can try this tutorial with codes can be downloaded. https://www.c-sharpcorner.com/article/jwt-authentication-with-refresh-tokens-in-net-6-0/ <br>

Your project used cookie so you should make the cookie expired more quickly. Then use refresh token to get access token by each request ,or use javascript timer to make this request at background every day to make an update.

huangapple
  • 本文由 发表于 2023年4月11日 06:19:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75981154.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定