做为前后端分离项目中,授权认证常用token令牌做为身份认证的方式,对于jwt令牌的获取、验证、解析以及存储,分别示例如下:
需要安装两个nuget包,分别为:IdentityModel和Microsoft.AspNetCore.Authentication.JwtBearer
1、JWT令牌生成及获取
//写Session或Cookies换成JWT IList<Claim> claims = new List<Claim> { new Claim(JwtClaimTypes.Id,admin.AdminId.ToString()), new Claim(JwtClaimTypes.Name,loginDto.UserName), new Claim(JwtClaimTypes.Email,loginDto.UserName), new Claim(JwtClaimTypes.Role,string.Join(",", "")) }; //JWT密钥 var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JwtConfig:Bearer:SecurityKey"])); //算法 var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); //过期时间 DateTime expires = DateTime.UtcNow.AddHours(10); //Payload负载 var token = new JwtSecurityToken( issuer: configuration["JwtConfig:Bearer:Issuer"], audience: configuration["JwtConfig:Bearer:Audience"], claims: claims, notBefore: DateTime.UtcNow, expires: expires, signingCredentials: cred ); var handler = new JwtSecurityTokenHandler(); //生成令牌 string jwt = handler.WriteToken(token);
2、JWT验证部分
JWT在Startup中的配置,主要用来使用固定的配置密钥对JWT的Token进行有效性验证。
//数据库连接 services.AddDbContext<SmsDBContext>(action => { action.UseSqlServer(Configuration.GetConnectionString("Default")); }); services.AddCors(option => { option.AddDefaultPolicy(policy => { //对应客户端withCredentials,需要设置具体允许的域名 policy.WithOrigins("http://web.a.com:88").AllowCredentials(); policy.AllowAnyMethod(); policy.AllowAnyHeader(); }); }); services.AddAuthentication(option => { option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer( option => { option.TokenValidationParameters = new TokenValidationParameters { //是否验证发行人 ValidateIssuer = true, ValidIssuer = Configuration["Authentication:JwtBearer:Issuer"],//发行人 //是否验证受众人 ValidateAudience = true, ValidAudience = Configuration["Authentication:JwtBearer:Audience"],//受众人 //是否验证密钥 ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Authentication:JwtBearer:SecurityKey"])), ValidateLifetime = true, //验证生命周期 RequireExpirationTime = true, //过期时间 ClockSkew = TimeSpan.Zero //平滑过期偏移时间 }; } );
另外,还需要配置相应的认证中间件和授权中间件
// 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(); app.UseSwagger(); string ApiName = "Rbac.Core"; app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/V1/swagger.json", $"{ApiName} V1"); c.SwaggerEndpoint("/swagger/gp/swagger.json", "登录模块"); c.SwaggerEndpoint("/swagger/mom/swagger.json", "业务模块"); c.SwaggerEndpoint("/swagger/dm/swagger.json", "其他模块"); //路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.RoutePrefix = "doc"; c.RoutePrefix = ""; }); } //app.UseHttpsRedirection(); //静态文件中间件 app.UseStaticFiles(); //路由中间件 app.UseRouting(); //跨域 app.UseCors(); //认证中间件 app.UseAuthentication(); //授权中间件 app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
经过上面配置,可以完成JWT令牌的生成及校验。
3、前端Axios的令牌保存及请求授权接口
前端接收到Api接口返回的token令牌后,应该把token保存起来,保存的位置可以是localStorage或sessionStorage,当访问授权接口时,从localStorage或sessionStorage中取出令牌,通过HTTP请求头进行访问。
import router from '../router' import axios from 'axios' let baseUrl = "http://localhost:5000/api"; axios.defaults.baseURL = baseUrl; axios.defaults.headers.common['Authorization'] = `bearer ${localStorage.getItem('token')}`; // 添加响应拦截器 axios.interceptors.response.use(function (response) { // 对响应数据做点什么 return response; }, function (error) { router.push("/"); return Promise.reject(error); }); export default { baseUrl, axios }
4、Swagger中的权限小锁配置
//开启权限小锁 options.OperationFilter<AddResponseHeadersFilter>(); options.OperationFilter<AppendAuthorizeToSummaryOperationFilter>(); options.OperationFilter<SecurityRequirementsOperationFilter>(); //在header中添加token,传递到后台 options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { Description = "JWT授权(数据将在请求头中进行传递)直接在下面框中输入Bearer {token}(注意两者之间是一个空格) \"", Name = "Authorization",//jwt默认的参数名称 In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中) Type = SecuritySchemeType.ApiKey });