asp.net core api 基于token的JWT bearer 的鉴权验证实现探索

.net的各种框架啥的都不是很熟悉,当时只是想怎么实现快速校验授权确保api是通过验证之后才能打开。
我说的快速就是不需要写重复的样板代码,通过总体控制,最后发现,似乎也只能通过注解实现,不过也算是比较合理的,不然无法区分哪些需要哪些不需要了

那么实现原理就设计到cookie,session, token,前面的session是需要服务器存档用户信息的,服务器压力比较大,token的实现原理,在登录之后返回 一个token, 之后再每一个接口提交都传递token,

都传递token可以通过请求头提交也可以通过get,post这些提交,我这里探索两者均实现。

问了一些网友,说要实现便捷授权可以实现拦截器,拦截器类似注解,
那么只是单纯的拦截器还不是根本,而且我还是没看懂所以然咋自己通过写拦截器代码实现,
最后不得不直接用框架jwt bearer实现

jwt bearer 接入是只需要添加注解Auth 就可以实现对指定方法的鉴权。

using coreapiauth;
using coreapiauth.TestWebApi.AuthCenter.Utility;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);



// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//注入JWT服务
builder.Services.AddScoped();


#region 注册JWT鉴权
var issuer = "study"; //Configuration["issuer"];
var audience = "lozn"; //Configuration["audience"];
var securityKey = "4A9A70D2-B8AD-42E1-B002-553BDEF4E76F";// Configuration["SecurityKey"];


//配置认证服务
builder.Services.AddAuthentication(x =>
{
    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
});

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) //默认授权机制名称
    .AddJwtBearer(options =>
    {


        options.TokenValidationParameters = new TokenValidationParameters();
        options.Events = new JwtBearerEvents()
        {
            OnMessageReceived = context =>
            {
                context.Token = context.Request.Query["access_token"];
                return Task.CompletedTask;
            }
        };
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true, //是否验证Issuer
            ValidateAudience = true, //是否验证Audience
            ValidateLifetime = true, //是否验证失效时间
            RequireExpirationTime = true, //过期时间
            ValidateIssuerSigningKey = true, //是否验证IssuerSigningKey
            ValidAudience = audience,
            ValidIssuer = issuer,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(securityKey)),
            //自定义校验规则:新登录后,之前的token无效
            //AudienceValidator = (audiences, securityToken, validationParameters) =>
            //{
            //    return audiences != null && audiences.FirstOrDefault().Equals(audience);
            //}
        };
    });
#endregion


var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}


//app.UseHttpsRedirection();


//1.先开启认证
app.UseAuthentication();
//2.再开启授权
app.UseAuthorization();



app.MapControllers();

app.Run();

网上的文章似乎有些将的不是 core api,有些是core api,但是和我这边开发工具生成的模板代码又不一样,所以我这边是这样子的。
其中

app.UseAuthentication();
app.UseAuthorization();

似乎影响了最后能否正常通过鉴权,我之前是成功获取了token,但是一直卡无法鉴权成功, 请求头应该传递什么,最后得出的结论:Authorization为请求头的key ,value为Bearer 登录返回的key
也可以通过get提交,上面的完整代码之所以可以get生效是因为有如下代码生效

options.Events = new JwtBearerEvents()
        {
            OnMessageReceived = context =>
            {
                context.Token = context.Request.Query["access_token"];
                return Task.CompletedTask;
            }
        };

那么访问

http://lozn.vaiwan.com/api/Auth/GetAuthData?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiYWRtaW4iLCJOaWNrTmFtZSI6Ik5ldENvcmUiLCJSb2xlIjoiQWRtaW5pc3RyYXRvciIsImV4cCI6MTY1NDA3MDY2NywiaXNzIjoic3R1ZHkiLCJhdWQiOiJsb3puIn0.7GQOQybhFLFXpL0FO31WNdm-o8MYJHS5F-y1xB-PQPU

我写的这个源码有两个地方都用到了秘钥,

其中在启动的代码中配置的是如下

options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true, //是否验证Issuer
            ValidateAudience = true, //是否验证Audience
            ValidateLifetime = true, //是否验证失效时间
            RequireExpirationTime = true, //过期时间
            ValidateIssuerSigningKey = true, //是否验证IssuerSigningKey
            ValidAudience = audience,
            ValidIssuer = issuer,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(securityKey)),
            //自定义校验规则:新登录后,之前的token无效
            //AudienceValidator = (audiences, securityToken, validationParameters) =>
            //{
            //    return audiences != null && audiences.FirstOrDefault().Equals(audience);
            //}
        };

而在登录的时候返回 token用到的代码

public string GetToken(string name)
            {
                /**
                 * Claims(Payload)
                 * Claims包含了一些跟这个token有关的重要信息。JWT标准规定的字段:
                 * 
                 * iss: The issuer of the token, 签发人
                 * sub: The subject of the token, 主题
                 * exp: Expiration Time. 过期时间(Unix时间戳格式)
                 * iat: Issued At. 签发时间(Unix时间戳格式)
                 * jti: JWT ID. 编号
                 * aud: audience. 受众
                 * nbf: Not Before. 生效时间
                 * 
                 * 除了规定的字段外,可以包含其他任何JSON兼容的字段。
                 * */
                var claims = new[]
                {
                new Claim(ClaimTypes.Name, name),
                new Claim("NickName", "NetCore"),
                new Claim("Role", "Administrator")
            };


                if (_configuration["SecurityKey"] == null)
                {
                    throw new Exception("please  config SecurityKey  issuer audience at appsettings.json");
           
                }

                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["SecurityKey"]));
                var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                var token = new JwtSecurityToken(
                    issuer: _configuration["issuer"], //签发人
                    audience: _configuration["audience"],
                    claims: claims,
                    expires: DateTime.Now.AddMinutes(20), //20分钟有效期
                    signingCredentials: credentials);
                var tokenStr = new JwtSecurityTokenHandler().WriteToken(token);
                return tokenStr;
            }

如果两者的issuer,audience,或者key不一致,一样是无法鉴权成功的,为了确保 SecurityKey在appsetting.json里面定义我直接加了检测,不存在直接抛出异常。
就可以成功实现访问,而非返回401,如果鉴权不成功是返回401的
最后能成功实现,还是参考了如下比较有参考意义的文章,前者并没有提到怎么去传递请求头,以及configuration参数怎么传递也没提及,所以搞的我一直没成功,
完整源码暂时不放出来了,因为第一篇文章已经算文章了,而我提供的program.cs也解决了如何读取configration的问题,以及写了一篇关于配置文件configration是啥玩意的问题。

https://www.cnblogs.com/xhubobo/p/14428578.html

https://blog.csdn.net/ma_jiang/article/details/106858593

你可能感兴趣的:(asp.net,java,后端,开发语言)