/// <summary> /// 获取基于JWT的Token /// </summary> /// <param name="claims">需要在登陆的时候配置</param> /// <param name="permissionRequirement">在startup中定义的参数</param> /// <returns></returns> public static dynamic BuildJwtToken(Claim[] claims, PermissionRequirement permissionRequirement) { var now = DateTime.Now; // 实例化JwtSecurityToken var jwt = new JwtSecurityToken( issuer: permissionRequirement.Issuer, audience: permissionRequirement.Audience, claims: claims, notBefore: now, expires: now.Add(permissionRequirement.Expiration), signingCredentials: permissionRequirement.SigningCredentials ); // 生成 Token var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt); //打包返回前台 var responseJson = new { success = true, token = encodedJwt, expires_in = permissionRequirement.Expiration.TotalSeconds, token_type = "Bearer" }; return(responseJson); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); #region Swagger UI Service var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath; services.AddSwaggerGen(c => { //遍历出全部的版本,做文档信息展示 typeof(ApiVersions).GetEnumNames().ToList().ForEach(version => { c.SwaggerDoc(version, new Info { // {ApiName} 定义成全局变量,方便修改 Version = version, Title = $"{ApiName} 接口文档", Description = $"{ApiName} HTTP API " + version, TermsOfService = "None", Contact = new Contact { Name = "Autho.JWT.Policy", Email = "*****@*****.**", Url = "https://www.jianshu.com/u/94102b59cc2a" } }); // 按相对路径排序,作者:Alby c.OrderActionsBy(o => o.RelativePath); }); //就是这里 var xmlPath = Path.Combine(basePath, "Autho.JWT.Policy.xml"); //这个就是刚刚配置的xml文件名 c.IncludeXmlComments(xmlPath, true); //默认的第二个参数是false,这个是controller的注释,记得修改 #region Token绑定到ConfigureServices //添加header验证信息 //c.OperationFilter<SwaggerHeader>(); // 发行人 var IssuerName = (Configuration.GetSection("Audience"))["Issuer"]; var security = new Dictionary <string, IEnumerable <string> > { { IssuerName, new string[] { } }, }; c.AddSecurityRequirement(security); //方案名称“Autho.JWT.Policy”可自定义,上下一致即可 c.AddSecurityDefinition(IssuerName, new ApiKeyScheme { Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"", Name = "Authorization", //jwt默认的参数名称 In = "header", //jwt默认存放Authorization信息的位置(请求头中) Type = "apiKey" }); #endregion }); #endregion #region 【授权】 #region 参数 //读取配置文件 var audienceConfig = Configuration.GetSection("Audience"); var symmetricKeyAsBase64 = audienceConfig["Secret"]; var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64); var signingKey = new SymmetricSecurityKey(keyByteArray); // 令牌验证参数 var tokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = signingKey, ValidateIssuer = true, ValidIssuer = audienceConfig["Issuer"], //发行人 ValidateAudience = true, ValidAudience = audienceConfig["Audience"], //订阅人 ValidateLifetime = true, ClockSkew = TimeSpan.Zero, RequireExpirationTime = true, }; var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256); // 如果要数据库动态绑定,这里先留个空,后边处理器里动态赋值 var permission = new List <PermissionItem>(); // 角色与接口的权限要求参数 var permissionRequirement = new PermissionRequirement( "/api/denied", // 拒绝授权的跳转地址(目前无用) permission, ClaimTypes.Role, //基于角色的授权 audienceConfig["Issuer"], //发行人 audienceConfig["Audience"], //听众 signingCredentials, //签名凭据 expiration: TimeSpan.FromSeconds(60 * 2) //接口的过期时间 ); #endregion //【授权】 services.AddAuthorization(options => { options.AddPolicy("Permission", policy => policy.Requirements.Add(permissionRequirement)); }); #endregion #region 【认证】 //2.1【认证】、官方JWT认证 services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(o => { o.TokenValidationParameters = tokenValidationParameters; o.Events = new JwtBearerEvents { OnAuthenticationFailed = context => { // 如果过期,则把<是否过期>添加到,返回头信息中 if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { context.Response.Headers.Add("Token-Expired", "true"); } return(Task.CompletedTask); } }; }); // 注入权限处理器 services.AddSingleton <IAuthorizationHandler, PermissionHandler>(); services.AddSingleton(permissionRequirement); #endregion }