ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

03-Jwt在.netcore中的实现

2020-08-31 08:31:38  阅读:302  来源: 互联网

标签:03 netcore Jwt JwtBearer token new claims configuration public


1)jwt的加密解密过程

jwt验证的核心就是加密解密的过程,掌握了这个过程,也就掌握了jwt的原理。jwt的三部分中,header和payload是明文的,能够直接读出来,签名Signature部分是进行了加密处理的。

Signature的加密过程

为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名即可。一般的编码是base64url编码格式。

例如:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

签名是用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方是否为它所称的发送方。

解密方也会拿着秘钥对token最对应的解密,然后将解密的内容和原文内容做对比,如果一样就没有被篡改。

2)代码实现主要包含两部分,授权中心(token颁发),api服务器(验证token)

相对来说颁发token比较简单,上代码

[HttpPost]
public string Login()
{
    var claims = new[]
    {
       new Claim(ClaimTypes.Name, "TestUser1"),
       new Claim("Role","Administrator"),//传递其他信息  
    };

    return CreateAccessToken(claims, _configuration);
}

private string CreateAccessToken(IEnumerable<Claim> claims, IConfiguration configuration, TimeSpan? expiration = null)
{
    var now = DateTime.UtcNow;

    var SecurityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(configuration["Authentication:JwtBearer:SecurityKey"]));

    var jwtSecurityToken = new JwtSecurityToken(
        issuer: configuration["Authentication:JwtBearer:Issuer"],
        audience: configuration["Authentication:JwtBearer:Audience"],
        claims: claims,
        notBefore: now,
        expires: now.Add(expiration ?? TimeSpan.FromSeconds(configuration.GetValue<long>("Authentication:JwtBearer:Expiration"))),
        signingCredentials: new SigningCredentials(SecurityKey, SecurityAlgorithms.HmacSha256)
    );

    return new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
}

这里只是省去了验证用户登录的过程,架设登录验证通过,直接生成token。

验证端相对代码逻辑会多一些,继续上代码:

public static void Configure(IServiceCollection services, IConfiguration configuration)
{
    if (bool.Parse(configuration["Authentication:JwtBearer:IsEnabled"]))
    {
        string authenticationScheme = JwtBearerDefaults.AuthenticationScheme;

        services.AddAuthentication(authenticationScheme)
            .AddJwtBearer(authenticationScheme, options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    SaveSigninToken = false,
                    ValidateActor = false,
                    ValidateTokenReplay = false,

                    // The signing key must match!
                    RequireSignedTokens = true,
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(configuration["Authentication:JwtBearer:SecurityKey"])),

                    // Validate the JWT Issuer (iss) claim
                    ValidateIssuer = true,
                    ValidIssuer = configuration["Authentication:JwtBearer:Issuer"],

                    // Validate the JWT Audience (aud) claim
                    RequireAudience = true,
                    ValidateAudience = true,
                    ValidAudience = configuration["Authentication:JwtBearer:Audience"],

                    // Validate the token expiry
                    RequireExpirationTime = true,
                    ValidateLifetime = true,

                    // If you want to allow a certain amount of clock drift, set that here
                    ClockSkew = TimeSpan.Zero
                };
            });
    }
}

这里面的配置信息和颁发端的配置要保持一致,否则无法验证通过。

验证端需要再控制器或者Action中加入验证,继续上代码

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    
    //Jwt
    AuthConfigurer.Configure(services, Configuration);
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    #region jwt
    //身份验证又称“认证”、“鉴权”,是指通过一定的手段,完成对用户身份的确认。 
    //身份验证的目的是确认当前所声称为某种身份的用户,确实是所声称的用户。
    app.UseAuthentication();//注意添加这一句,启用验证
    #endregion

    app.UseRouting();

    //授权一般是指对信息安全或计算机安全相关的资源定义与授予访问权限,尤指访问控制。
    //动词“授权”可指定义访问策略与接受访问。
    //例如,人力资源人员通常被授权访问员工记录,而这个策略通常被形式化为计算机系统中的访问控制规则。
    //在运行期间,系统使用已定义的访问控制规则决定是接受还是拒绝经过身份验证的访问请求。
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

控制器访问限制:

[ApiController]
[Route("[controller]/[action]")]
//[Authorize]
public class BaseController : ControllerBase, IActionFilter
{
    protected IEnumerable<Claim> claims { get; set; }

    public void OnActionExecuted(ActionExecutedContext context)
    {

    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        //claims = context.HttpContext.AuthenticateAsync().Result.Principal.Claims;//这种方式必须在控制器上方拥有[Authorize]特性时才可用
        claims = context.HttpContext.User.Claims;
    }
}



[ApiController]
[Route("[controller]/[action]")]
[Authorize]
public class PatientController : BaseController
{
    private readonly ILogger<PatientController> _logger;

    public PatientController(ILogger<PatientController> logger)
    {
        _logger = logger;
    }

    [AllowAnonymous]
    [HttpGet]
    public async Task<string> GetByPatientId(long patientId)
    {
        return await Task.FromResult($"GetByPatientId:{patientId}");
    }

    [HttpPost]
    public async Task<Patient> CreateorUpdatePatient([FromBody] Patient patient)
    {
        var claims = this.claims;
        patient.PatientName = "PatientName";
        return await Task.FromResult(patient);
    }
}

这里我们自定义了一个控制器的基类,实现了接口IActionFilter的两个方法,在控制器执行中,先执行了 OnActionExecuting,这里面可以获得token中的所有Claims,两种方法见代码,一种是直接使用

HttpContext.User.Claims

一种是在控制器拥有[Authorize]特性,然后可以使用

HttpContext.AuthenticateAsync().Result.Principal.Claims;

综上,jwt就可以实现了。至于过期时候刷新token,异地登录之后本地token失效等逻辑,单纯的依靠jwt是无法实现的,有想法的同学欢迎探讨。

附代码(支持国产):demo

标签:03,netcore,Jwt,JwtBearer,token,new,claims,configuration,public
来源: https://www.cnblogs.com/vigorous/p/13587697.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有