自定义Token失效或过期的响应处理以及Bearer名称或者取消授权时要输入的前缀
问题点:
1:我们在Swagger授权时往往要输入前缀,感觉比较麻烦
2:Token过期,前端页面没有跳转只是抛一个异常,需要刷新一下再登录才行,体验差
private const string MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; public void ConfigureServices(IServiceCollection services) { services.AddAddCorsInfo(MyAllowSpecificOrigins);//允许跨域 services.AddAuthorizationSetup(Configuration);//添加验证服务,jwt授权验证 services.AddSwaggerGenTask(); //配置Swagger }
主要代码如下:
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; using QzjcService.Models; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace QzjcService.SetUp { public static class AuthorizationSetup { public static void AddAuthorizationSetup(this IServiceCollection services, Microsoft.Extensions.Configuration.IConfiguration configuration) { if (services == null) throw new ArgumentNullException(nameof(services)); // 1【授权】、这个和上边的异曲同工,好处就是不用在controller中,写多个 roles 。 // 然后这么写 [Authorize(Policy = "Admin")] services.AddAuthorization(options => { options.AddPolicy("User", policy => policy.RequireRole("User").Build()); options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin", "System")); }); //读取配置文件 var symmetricKeyAsBase64 = configuration["Jwt:key"]; var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64); var signingKey = new SymmetricSecurityKey(keyByteArray); var Issuer = configuration["Jwt:issuer"]; var Audience = configuration["Jwt:audience"]; // 令牌验证参数 var tokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = signingKey, ValidateIssuer = true, ValidIssuer = Issuer,//发行人 ValidateAudience = true, ValidAudience = Audience,//订阅人 ValidateLifetime = true, ClockSkew = TimeSpan.FromSeconds(30), RequireExpirationTime = true, }; //2.1【认证】、core自带官方JWT认证 // 开启Bearer认证 services.AddAuthentication(o => { o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) // 添加JwtBearer服务 .AddJwtBearer(o => { o.TokenValidationParameters = tokenValidationParameters; o.Events = new JwtBearerEvents { OnAuthenticationFailed = context => { // 如果过期,则把<是否过期>添加到,返回头信息中 //if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) //{ // context.Response.Headers.Add("Token-Expired", "true"); //} if (!context.Response.Headers.Any(c => c.Key.Contains("Access-Control-Allow-Origin"))) context.Response.Headers.Add("Access-Control-Allow-Origin", "*");//这里需要处理一下 context.Response.Headers.Add("Token-Expired", "true"); context.Response.Headers.Add("LmzTokenValide", "false"); return Task.CompletedTask; }, OnMessageReceived = recevied => { var headStr = recevied.HttpContext.Request.Headers[ConstData.Authorization].ToString(); if (!headStr.IsNonOrEmpty()) { if (!headStr.Contains(ConstData.TokenBearer))//处理 不输入 Bearer会自动加上 { string autoAuthHead = $"{ConstData.TokenBearer}{headStr}"; recevied.HttpContext.Request.Headers.Remove(ConstData.Authorization); recevied.HttpContext.Request.Headers.Add(ConstData.Authorization, autoAuthHead); } } return Task.CompletedTask; } }; }); } } }
允许跨域等
using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace QzjcService.ServicesExtend.CorsInfo { public static class AddCorsInfo { /// <summary> /// IServiceCollection 扩展函数 /// </summary> /// <param name="services"></param> /// <param name="MyAllowSpecificOrigins"></param> public static void AddAddCorsInfo(this IServiceCollection services,string MyAllowSpecificOrigins) { //允许跨域 services.AddCors(options => { options.AddPolicy(MyAllowSpecificOrigins, builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("Token-Expired").WithExposedHeaders("LmzTokenValide") ); }); } } }
启用中间件服务生成Swagge
app.UseSwagger(); //启用中间件服务生成SwaggerUI,指定Swagger JSON终结点 app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Web App V1"); //c.SwaggerEndpoint("v1/swagger.json", "Web App V1"); c.RoutePrefix = string.Empty;//设置根节点访问 }); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); });
配置Swagger
using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.Filters; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; namespace QzjcService.ServicesExtend.SwaggerInfo { public static class SwaggerGenTask { /// <summary> /// IServiceCollection 扩展函数 /// </summary> /// <param name="services"></param> public static void AddSwaggerGenTask(this IServiceCollection services) { //配置Swagger //注册Swagger生成器,定义一个Swagger 文档 services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Version = "v1", Title = "**平台接口文档", Description = "***大数据平台接口文档" }); // 为 Swagger 设置xml文档注释路径 var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); // 在header中添加token,传递到后台 c.OperationFilter<SecurityRequirementsOperationFilter>(); //region Token绑定到ConfigureServices,swagger右上角显示Token输入框 c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"", Name = "Authorization",//jwt默认的参数名称 In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中) Type = SecuritySchemeType.ApiKey }); }); } } }
通常我们的网站过期时间过长,修改时间太短再发布到服务器会影响到其他使用的使用,我们可以这样处理:
此时页面就方便跳转了,需要注意的跨域那块需要处理不然页面拿不到信息
如有疑问或者错误的地方,请跟帖,本人会第一时间答复以及相互学习,谢谢!个人会不断的上传自己的学习心得!
好了今天就先到这里,下次有时间再更新,如果存在不合理的地方,欢迎大家多多指教留言!!!