mirror of
http://git.coreshop.cn/jianweie/coreshoppro.git
synced 2025-12-06 16:13:26 +08:00
299 lines
13 KiB
C#
299 lines
13 KiB
C#
/***********************************************************************
|
||
* Project: CoreCms
|
||
* ProjectName: 核心内容管理系统
|
||
* Web: https://www.corecms.net
|
||
* Author: 大灰灰
|
||
* Email: jianweie@163.com
|
||
* CreateTime: 2021/1/31 21:45:10
|
||
* Description: 暂无
|
||
***********************************************************************/
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.IdentityModel.Tokens.Jwt;
|
||
using System.Linq;
|
||
using System.Security.Claims;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using CoreCms.Net.Auth.Policys;
|
||
using CoreCms.Net.Configuration;
|
||
using CoreCms.Net.Utility.Extensions;
|
||
using Microsoft.AspNetCore.Authentication;
|
||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||
using Microsoft.AspNetCore.Authorization;
|
||
using Microsoft.AspNetCore.Http;
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
using Microsoft.IdentityModel.Tokens;
|
||
using NETCore.Encrypt;
|
||
|
||
namespace CoreCms.Net.Auth
|
||
{
|
||
/// <summary>
|
||
/// Db 启动服务
|
||
/// </summary>
|
||
public static class AuthorizationSetup
|
||
{
|
||
/// <summary>
|
||
/// 后台管理员jwt初始化设置
|
||
/// </summary>
|
||
/// <param name="services"></param>
|
||
public static void AddAuthorizationSetupForAdmin(this IServiceCollection services)
|
||
{
|
||
if (services == null) throw new ArgumentNullException(nameof(services));
|
||
|
||
#region 参数
|
||
//读取配置文件
|
||
var symmetricKeyAsBase64 = AppSettingsHelper.GetMachineRandomKey(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,//发行人 //Issuer,这两项和前面签发jwt的设置一致
|
||
ValidateAudience = true, //是否验证Audience
|
||
ValidAudience = audience,//订阅人
|
||
ValidateLifetime = true,//是否验证失效时间
|
||
ClockSkew = TimeSpan.FromSeconds(4),
|
||
RequireExpirationTime = true,
|
||
};
|
||
|
||
// core自带官方JWT认证,开启Bearer认证
|
||
services.AddAuthentication(o =>
|
||
{
|
||
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
|
||
o.DefaultChallengeScheme = nameof(ApiResponseForAdminHandler);
|
||
o.DefaultForbidScheme = nameof(ApiResponseForAdminHandler);
|
||
})
|
||
// 添加JwtBearer服务
|
||
.AddJwtBearer(o =>
|
||
{
|
||
o.TokenValidationParameters = tokenValidationParameters;
|
||
o.Events = new JwtBearerEvents
|
||
{
|
||
OnMessageReceived = context =>
|
||
{
|
||
var token = context.Request.Headers["Authorization"].ObjectToString().Replace("Bearer ", "");
|
||
if (string.IsNullOrEmpty(token))
|
||
{
|
||
context.Response.Headers.Append("Token-Error-Token", "authorization decryption failure!");
|
||
}
|
||
else
|
||
{
|
||
context.Token = EncryptProvider.AESDecrypt(token, AppSettingsConstVars.JwtConfigSecretKey);
|
||
}
|
||
return Task.CompletedTask;
|
||
},
|
||
OnChallenge = context =>
|
||
{
|
||
context.Response.Headers.Append("Token-Error", context.ErrorDescription);
|
||
return Task.CompletedTask;
|
||
},
|
||
OnAuthenticationFailed = context =>
|
||
{
|
||
var token = context.Request.Headers["Authorization"].ObjectToString().Replace("Bearer ", "");
|
||
if (string.IsNullOrEmpty(token))
|
||
{
|
||
context.Response.Headers.Append("Token-Error-Token", "token is wrong!");
|
||
}
|
||
|
||
//进行aes解密
|
||
var decodeToken = EncryptProvider.AESDecrypt(token, AppSettingsConstVars.JwtConfigSecretKey);
|
||
if (string.IsNullOrEmpty(decodeToken))
|
||
{
|
||
context.Response.Headers.Append("Token-Error-Token", "token decryption failure!");
|
||
}
|
||
|
||
var jwtToken = (new JwtSecurityTokenHandler()).ReadJwtToken(decodeToken);
|
||
|
||
if (jwtToken.Issuer != issuer)
|
||
{
|
||
context.Response.Headers.Append("Token-Error-Iss", "issuer is wrong!");
|
||
}
|
||
|
||
if (jwtToken.Audiences.FirstOrDefault() != audience)
|
||
{
|
||
context.Response.Headers.Append("Token-Error-Aud", "Audience is wrong!");
|
||
}
|
||
|
||
// 如果过期,则把<是否过期>添加到,返回头信息中
|
||
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
|
||
{
|
||
context.Response.Headers.Append("Token-Expired", "true");
|
||
}
|
||
return Task.CompletedTask;
|
||
}
|
||
};
|
||
})
|
||
.AddScheme<AuthenticationSchemeOptions, ApiResponseForAdminHandler>(nameof(ApiResponseForAdminHandler), o => { });
|
||
|
||
|
||
// 注入权限处理器
|
||
services.AddScoped<IAuthorizationHandler, PermissionForAdminHandler>();
|
||
services.AddSingleton(permissionRequirement);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 前端客户jwt初始化设置
|
||
/// </summary>
|
||
/// <param name="services"></param>
|
||
public static void AddAuthorizationSetupForClient(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 * 30)//接口的过期时间
|
||
);
|
||
#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(4),
|
||
RequireExpirationTime = true,
|
||
};
|
||
|
||
// core自带官方JWT认证,开启Bearer认证
|
||
services.AddAuthentication(o =>
|
||
{
|
||
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
|
||
o.DefaultChallengeScheme = nameof(ApiResponseForClientHandler);
|
||
o.DefaultForbidScheme = nameof(ApiResponseForClientHandler);
|
||
})
|
||
// 添加JwtBearer服务
|
||
.AddJwtBearer(o =>
|
||
{
|
||
o.TokenValidationParameters = tokenValidationParameters;
|
||
o.Events = new JwtBearerEvents
|
||
{
|
||
OnMessageReceived = context =>
|
||
{
|
||
var token = context.Request.Headers["Authorization"].ObjectToString().Replace("Bearer ", "");
|
||
if (string.IsNullOrEmpty(token))
|
||
{
|
||
context.Response.Headers.Append("Token-Error-Token", "authorization decryption failure!");
|
||
}
|
||
else
|
||
{
|
||
context.Token = EncryptProvider.AESDecrypt(token, AppSettingsConstVars.JwtConfigSecretKey);
|
||
}
|
||
return Task.CompletedTask;
|
||
},
|
||
OnChallenge = context =>
|
||
{
|
||
context.Response.Headers.Append("Token-Error", context.ErrorDescription);
|
||
return Task.CompletedTask;
|
||
},
|
||
OnAuthenticationFailed = context =>
|
||
{
|
||
var token = context.Request.Headers["Authorization"].ObjectToString().Replace("Bearer ", "");
|
||
if (string.IsNullOrEmpty(token))
|
||
{
|
||
context.Response.Headers.Append("Token-Error-Token", "token is wrong!");
|
||
}
|
||
|
||
//进行aes解密
|
||
var decodeToken = EncryptProvider.AESDecrypt(token, AppSettingsConstVars.JwtConfigSecretKey);
|
||
if (string.IsNullOrEmpty(decodeToken))
|
||
{
|
||
context.Response.Headers.Append("Token-Error-Token", "token decryption failure!");
|
||
}
|
||
|
||
var jwtToken = (new JwtSecurityTokenHandler()).ReadJwtToken(decodeToken);
|
||
|
||
if (jwtToken.Issuer != issuer)
|
||
{
|
||
context.Response.Headers.Append("Token-Error-Iss", "issuer is wrong!");
|
||
}
|
||
|
||
if (jwtToken.Audiences.FirstOrDefault() != audience)
|
||
{
|
||
context.Response.Headers.Append("Token-Error-Aud", "Audience is wrong!");
|
||
}
|
||
|
||
// 如果过期,则把<是否过期>添加到,返回头信息中
|
||
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
|
||
{
|
||
context.Response.Headers.Append("Token-Expired", "true");
|
||
}
|
||
return Task.CompletedTask;
|
||
}
|
||
};
|
||
})
|
||
.AddScheme<AuthenticationSchemeOptions, ApiResponseForClientHandler>(nameof(ApiResponseForClientHandler), o => { });
|
||
|
||
|
||
// 注入权限处理器
|
||
services.AddScoped<IAuthorizationHandler, PermissionForClientHandler>();
|
||
services.AddSingleton(permissionRequirement);
|
||
}
|
||
|
||
|
||
}
|
||
}
|