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
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);
|
|
}
|
|
}
|
|
}
|
|
|