You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

118 lines
5.0 KiB

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Znyc.CloudCar.Auth.Policys;
using Znyc.CloudCar.Configuration;
using Znyc.CloudCar.Utility.Extensions;
using static Znyc.CloudCar.Configuration.GlobalConstVars;
namespace Znyc.CloudCar.Core.Config
{
public static class AuthorizationSetup
{
public static void AddAuthorizationSetup(this IServiceCollection services)
{
if (services == null) throw new ArgumentNullException(nameof(services));
#region 参数
//读取配置文件
var symmetricKeyAsBase64 = AppSettingsConstVars.JwtConfigSecretKey;
var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
var signingKey = new SymmetricSecurityKey(keyByteArray);
var issuer = AppSettingsConstVars.JwtConfigIssuer;
var audience = AppSettingsConstVars.JwtConfigAudience;
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
// 如果要数据库动态绑定,这里先留个空,后边处理器里动态赋值
var permission = new List<PermissionItem>();
// 角色与接口的权限要求参数
var permissionRequirement = new PermissionRequirement(
"/api/denied",// 拒绝授权的跳转地址(目前无用)
permission,
ClaimTypes.Role,//基于角色的授权
issuer,//发行人
audience,//听众
signingCredentials,//签名凭据
expiration: TimeSpan.FromSeconds(60 * 60 * 24)//接口的过期时间
);
#endregion
// 复杂的策略授权
services.AddAuthorization(options =>
{
options.AddPolicy(Permissions.Name, policy => policy.Requirements.Add(permissionRequirement));
});
// 令牌验证参数
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true, //是否验证SecurityKey
IssuerSigningKey = signingKey, //拿到SecurityKey
ValidateIssuer = true, //是否验证Issuer
ValidIssuer = issuer,//发行人
ValidateAudience = true, //是否验证Audience
ValidAudience = audience,//订阅人
ValidateLifetime = true, //是否验证失效时间
ClockSkew = TimeSpan.FromSeconds(60),
RequireExpirationTime = true,
};
// core自带官方JWT认证,开启Bearer认证
services.AddAuthentication(o =>
{
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = nameof(ApiResponseHandler);
o.DefaultForbidScheme = nameof(ApiResponseHandler);
})
// 添加JwtBearer服务
.AddJwtBearer(o =>
{
o.TokenValidationParameters = tokenValidationParameters;
o.Events = new JwtBearerEvents
{
OnChallenge = context =>
{
context.Response.Headers.Add("Token-Error", context.ErrorDescription);
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
var token = context.Request.Headers["Authorization"].ObjectToString().Replace("Bearer ", "");
var jwtToken = (new JwtSecurityTokenHandler()).ReadJwtToken(token);
if (jwtToken.Issuer != issuer)
{
context.Response.Headers.Add("Token-Error-Iss", "issuer is wrong!");
}
if (jwtToken.Audiences.FirstOrDefault() != audience)
{
context.Response.Headers.Add("Token-Error-Aud", "Audience is wrong!");
}
// 如果过期,则把<是否过期>添加到,返回头信息中
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("Token-Expired", "true");
}
return Task.CompletedTask;
}
};
})
.AddScheme<AuthenticationSchemeOptions, ApiResponseHandler>(nameof(ApiResponseHandler), o => { });
// 注入权限处理器
services.AddScoped<IAuthorizationHandler, PermissionHandler>();
services.AddSingleton(permissionRequirement);
}
}
}