ASP.NET Core Jwt 实现 signinmanager 声明

Posted

技术标签:

【中文标题】ASP.NET Core Jwt 实现 signinmanager 声明【英文标题】:ASP.NET Core Jwt implement signinmanager claims 【发布时间】:2019-04-14 20:04:12 【问题描述】:

我已经实现了 Jwt 作为对我的用户进行身份验证的一种方式。但是,我被困在如何在我的应用程序上针对角色做某些事情。目前我的 Jwt Token 包含用户的 email、phone、id 和他们拥有的角色列表。

我用那个令牌做什么是这样的:

[TypeFilter(typeof(ValidateRolesFilter), Arguments = new object[] 
        ApplicationGlobals.ApplicationSecretKey, RoleGlobals.SystemAdministrator
)]
public IActionResult Index()

    return View();

我的 Typefilter 包含一个将令牌发送到另一个应用程序以验证我的用户是否可以访问该函数的休息请求。然而, 当谈到视图时,我被卡住了。我想分割某些容器以允许具有某些角色的某些用户查看。

我有一个想法,如果我像非 jwt 应用程序一样将用户声明添加到 signinmanager,我将能够从 httpcontext 获取声明。但是,我不知道我所拥有的是否可以与使用 jwt 的应用程序一起使用。

public async Task SignInUserAsync(TIdentityUser user, bool isPersistent, IEnumerable<Claim> customClaims)

    var claimsPrincipal = await _signInManager.CreateUserPrincipalAsync(user);
    var identity = claimsPrincipal.Identity as ClaimsIdentity;
    var claims = (from c in claimsPrincipal.Claims select c).ToList();
    var savedClaims = claims;
    foreach (var item in claims)
    
        identity.RemoveClaim(item);
    
    if (customClaims != null)
    
        identity.AddClaim(savedClaims[0]);
        identity.AddClaim(savedClaims[1]);
        identity.AddClaim(savedClaims[2]);
        identity.AddClaims(customClaims);
    
    await _signInManager.Context.SignInAsync(IdentityConstants.ApplicationScheme,
        claimsPrincipal,
        new AuthenticationProperties  IsPersistent = isPersistent );

【问题讨论】:

你检查过这个吗? ***.com/questions/18677837/… 【参考方案1】:

我最近在 JWT 上做一个合作项目。我写了一个中间件,当用户向 api 请求时,它由身份验证中间件检查。我从 db 中读取了 userRole 并将其放入我共享中间件代码的身份原则中。

这里我阅读了JWT中间部分提取用户信息

public class AuthenticationMiddleware

    private readonly RequestDelegate _next;

    // Dependency Injection
    public AuthenticationMiddleware(RequestDelegate next)
    
        _next = next;
    

    public async Task Invoke(HttpContext context)
    
        string authHeader = context.Request.Headers["Authorization"];

        if (authHeader != null)
                      
            int startPoint = authHeader.IndexOf(".") + 1;               
            int endPoint = authHeader.LastIndexOf(".");

            var tokenString = authHeader.Substring(startPoint, endPoint - startPoint).Split(".");
            var token = tokenString[0].ToString()+"==";

            var credentialString = Encoding.UTF8
                .GetString(Convert.FromBase64String(token));

            // Splitting the data from Jwt
            var credentials = credentialString.Split(new char[]  ':',',' );

            // Trim this string.
            var userRule = credentials[5].Replace("\"", ""); 
            var userName = credentials[3].Replace("\"", "");

             // Identity Principal
            var claims = new[]
            
                new Claim("name", userName),
                new Claim(ClaimTypes.Role, userRule),

            ;
            var identity = new ClaimsIdentity(claims, "basic");
            context.User = new ClaimsPrincipal(identity);
        
        await _next(context);
    



在startup.cs中你需要在configure method中调用这个中间件

 app.UseMiddleware<AuthenticationMiddleware>();

在控制器中

 [HttpGet("GetUsers")]
  [Authorize(Roles = "admin")]
    public ActionResult GetUsers()
    
        var users = _authRepository.GetUsers();
        return Ok(users);
    

如果您需要任何帮助,请发表评论。这个实现真的对我有用。检查我关于该主题的存储库:https://github.com/hidayatarg/Asp.net-Core-2.1-Jwt-Authentication-Middleware https://github.com/hidayatarg/Decode-JWT-Token

【讨论】:

您好,感谢您的回答。我尝试了这种方法,但后来我需要一个更自定义的函数,这就是我改用 typefilter 的原因。 因为 Jwt 签署了我们请求的标头。在这里,我正在阅读标题,特别是中间部分 jwt,如果您想查看完整示例,请查看我的 repo github.com/hidayatarg/…【参考方案2】:

JSON Web Tokens 由三部分组成,由点 (.) 分隔,分别是:Header、Payload、Signature。因此,JWT 通常看起来像 xxxxx.yyyyy.zzzzz。token 的第二部分是有效负载,它包含索赔。

您可以解码访问令牌以获取与您的角色相关的声明:

How to decode JWT Token? 。

Decoding and verifying JWT token using System.IdentityModel.Tokens.Jwt

如果您使用 Owin OpenID Connect 中间件从身份提供商(如 Azure AD、身份服务器 4...)对用户进行身份验证。您可以在 OnTokenValidated 事件下向主体添加其他声明。

编辑:

您还可以在登录前将声明(解码并获取声明)添加到用户上下文:

 var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme, ClaimTypes.Name, ClaimTypes.Role);
 identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, loginData.Username));
 identity.AddClaim(new Claim(ClaimTypes.Name, loginData.Username));
 //add your custom claims 
 ....

 var principal = new ClaimsPrincipal(identity);
 await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties  IsPersistent = loginData.RememberMe );

参考:http://future-shock.net/blog/post/creating-a-simple-login-in-asp.net-core-2-using-authentication-and-authorization-not-identity

然后您可以访问视图中的声明,例如:

@foreach (var item in Context.User.Claims)

    <p>@item.Value</p> 
; 

【讨论】:

在客户端解码令牌后,如何将其存储在 httpcontext 中以将其传递给视图? 如果可能,我宁愿不使用 cookie @JianYA ,只需将角色声明存储到 viewbag 中,根据该值在视图中添加显示/隐藏内容。 但这是否意味着如果我将角色声明存储到 viewbag 中,如果我有类似导航菜单的内容,其中包含某个角色的链接,我不需要为整个应用程序? @JianYA,查看编辑回复,您可以存储在用户声明或服务器端存储中。

以上是关于ASP.NET Core Jwt 实现 signinmanager 声明的主要内容,如果未能解决你的问题,请参考以下文章

ASP.net Core 2.0 JWT 令牌刷新

asp.net core + angular2 JWT 承载

Jwt 和 ASP.NET CORE 授权 AspNetRoleClaims

ASP.NET Core 使用 JWT 自定义角色/策略授权需要实现的接口

无法使用 ASP.NET Core 从 JWT 令牌获取声明

ASP.NET Core 搭载 Envoy 实现微服务身份认证(JWT)