添加项目文件。
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "5.0.10",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using ZhiZhun.AuthenticationCenter.Utility;
|
||||
using ZhiZhun.AuthenticationCenter.Utility.RSA;
|
||||
|
||||
namespace Zhaoxi.NET6.AuthenticationCenter.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class JWTController : ControllerBase
|
||||
{
|
||||
#region MyRegion
|
||||
private ILogger<JWTController> _logger = null;
|
||||
private IJWTService _iJWTService = null;
|
||||
private readonly IConfiguration _iConfiguration;
|
||||
public JWTController(ILoggerFactory factory,
|
||||
ILogger<JWTController> logger,
|
||||
IConfiguration configuration
|
||||
, IJWTService service)
|
||||
{
|
||||
this._logger = logger;
|
||||
this._iConfiguration = configuration;
|
||||
this._iJWTService = service;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
[Route("GetKey")]
|
||||
[HttpGet]
|
||||
public string GetKey()
|
||||
{
|
||||
string keyDir = Directory.GetCurrentDirectory();
|
||||
if (RSAHelper.TryGetKeyParameters(keyDir, false, out RSAParameters keyParams) == false)
|
||||
{
|
||||
keyParams = RSAHelper.GenerateAndSaveKey(keyDir, false);
|
||||
}
|
||||
|
||||
return JsonConvert.SerializeObject(keyParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据库校验
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <returns></returns>
|
||||
[Route("Login")]
|
||||
[HttpPost]
|
||||
public IResponseOutput Login([FromForm] string name, [FromForm] string password)
|
||||
{
|
||||
Console.WriteLine($"This is Login name={name} password={password}");
|
||||
if ("Eleven".Equals(name, StringComparison.OrdinalIgnoreCase) && "123456".Equals(password))//应该数据库
|
||||
{
|
||||
UserBasicInfo currentUser = new UserBasicInfo()
|
||||
{
|
||||
//Id = 123,
|
||||
//Account = "xuyang@zhaoxiEdu.Net",
|
||||
//EMail = "57265177@qq.com",
|
||||
//Mobile = "18664876671",
|
||||
//Sex = 1,
|
||||
//Age = 33,
|
||||
//Name = "Eleven",
|
||||
//Role = "Admin"
|
||||
};
|
||||
|
||||
string token = this._iJWTService.GetToken(currentUser);
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
return ResponseOutput.Ok("Token颁发成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
return ResponseOutput.NotOk("Token获取失败");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return ResponseOutput.NotOk("验证失败");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 生成Token+RefreshToken
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <returns></returns>
|
||||
[Route("LoginWithRefresh")]
|
||||
[HttpPost]
|
||||
public IResponseOutput LoginWithRefresh([FromForm] string name, [FromForm] string password)
|
||||
{
|
||||
Console.WriteLine($"This is LoginWithRefresh name={name} password={password}");
|
||||
|
||||
if ("Eleven".Equals(name, StringComparison.OrdinalIgnoreCase) && "123456".Equals(password))//应该数据库
|
||||
{
|
||||
UserBasicInfo currentUser = new UserBasicInfo()
|
||||
{
|
||||
//Id = 123,
|
||||
//Account = "xuyang@zhaoxiEdu.Net",
|
||||
//EMail = "57265177@qq.com",
|
||||
//Mobile = "18664876671",
|
||||
//Sex = 1,
|
||||
//Age = 33,
|
||||
//Name = "Eleven",
|
||||
//Role = "Admin"
|
||||
};
|
||||
|
||||
var tokenPair = this._iJWTService.GetTokenWithRefresh(currentUser);
|
||||
if (tokenPair != null && !string.IsNullOrEmpty(tokenPair.Item1))
|
||||
{
|
||||
|
||||
return ResponseOutput.Ok(new {
|
||||
Token = tokenPair.Item1,
|
||||
RefreshToken = tokenPair.Item2});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
return ResponseOutput.NotOk("颁发token失败");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return ResponseOutput.NotOk("验证失败");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[Route("RefreshToken")]
|
||||
[HttpPost]
|
||||
public IResponseOutput RefreshToken([FromForm] string refreshToken)
|
||||
{
|
||||
|
||||
var token = this._iJWTService.GetTokenByRefresh(refreshToken);
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
|
||||
return ResponseOutput.Ok("刷新Token成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return ResponseOutput.NotOk("刷新token失败");
|
||||
}
|
||||
|
||||
|
||||
#region Check refreshToken
|
||||
//string sResult = JWTTokenDeserialize.AnalysisToken(refreshToken);
|
||||
//var refreshTokenResult = await base.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
|
||||
//var expires = refreshTokenResult?.Principal?.Claims?.First(c => c.Type.Equals("expires"))?.Value ?? DateTime.Now.AddMinutes(-1).ToString();
|
||||
//if (DateTime.Parse(expires) > DateTime.Now)//有效期验证
|
||||
//{
|
||||
// var token = this._iJWTService.GetTokenByRefresh(refreshToken);
|
||||
// if (!string.IsNullOrEmpty(token))
|
||||
// {
|
||||
// return JsonConvert.SerializeObject(new AjaxResult<string>()
|
||||
// {
|
||||
// Result = true,
|
||||
// Message = "刷新Token成功",
|
||||
// TValue = token,
|
||||
// OtherValue = refreshToken//写在OtherValue
|
||||
// });
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return JsonConvert.SerializeObject(new AjaxResult<string>()
|
||||
// {
|
||||
// Result = false,
|
||||
// Message = "刷新token失败",
|
||||
// TValue = ""
|
||||
// });
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// return JsonConvert.SerializeObject(new AjaxResult<string>()
|
||||
// {
|
||||
// Result = false,
|
||||
// Message = "RefreshToken过期了",
|
||||
// TValue = ""
|
||||
// });
|
||||
//}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Grpc.Core;
|
||||
using gRPC.ZHiZHUN.AuthServer.protos;
|
||||
using ZhiZhun.AuthenticationCenter.User;
|
||||
using ZhiZhun.AuthenticationCenter.Utility;
|
||||
|
||||
namespace ZhiZhun.AuthenticationCenter.GrpcService
|
||||
{
|
||||
public class GrpcTokenService: TokenGrpcService.TokenGrpcServiceBase
|
||||
{
|
||||
private readonly IJWTService _jwtService;
|
||||
|
||||
public GrpcTokenService(IJWTService jwtService)
|
||||
{
|
||||
_jwtService = jwtService;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public override Task<GetTokenResponse> GetUserToken(GetTokenReuqest request, ServerCallContext context)
|
||||
{
|
||||
|
||||
string token = _jwtService.GetToken(new UserBasicInfo()
|
||||
{
|
||||
Id = Guid.Parse(request.Id),
|
||||
RealName = request.RealName,
|
||||
ReviewerCode = request.ReviewerCode,
|
||||
UserName = request.UserName,
|
||||
UserTypeEnum = (UserType)request.UserTypeEnumInt,
|
||||
UserTypeShortName = request.UserTypeShortName
|
||||
});
|
||||
|
||||
|
||||
return Task.FromResult(new GetTokenResponse(){Code = 1,Token = token });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>default</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DocumentationFile>D:\新工作\IRaCIS\IRaCIS.Core5.0.API\ZhiZhunAuthenticationCenter\ZhiZhun.AuthenticationCenter.xml</DocumentationFile>
|
||||
<NoWarn>1701;1702;1591;</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Protos\GrpcToken.proto" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Grpc.AspNetCore" Version="2.40.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.15.0" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.2.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.2.3" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.15.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\IRaCIS.Core.Infrastructure\IRaCIS.Core.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Protobuf Include="Protos\GrpcToken.proto" GrpcServices="Server" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Security.Authentication;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Serilog;
|
||||
using ZhiZhun.AuthenticationCenter;
|
||||
|
||||
namespace Zhaoxi.NET6.AuthenticationCenter
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Information()
|
||||
.WriteTo.File("logs\\log.txt",
|
||||
rollingInterval: RollingInterval.Day,
|
||||
rollOnFileSizeLimit: true)
|
||||
.CreateLogger();
|
||||
|
||||
try
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Information(e.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args)
|
||||
{
|
||||
|
||||
var configuration = new ConfigurationBuilder().SetBasePath(Environment.CurrentDirectory)
|
||||
.AddJsonFile("appsettings.json")
|
||||
.Build();
|
||||
|
||||
return Host.CreateDefaultBuilder(args)
|
||||
.UseWindowsService()
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.ConfigureKestrel(options =>
|
||||
{
|
||||
//如果放在内网,不想用https 那么需要在这里设置
|
||||
//Setup a HTTP / 2 endpoint without TLS.
|
||||
options.ListenLocalhost(7200, o => o.Protocols =
|
||||
HttpProtocols.Http2);
|
||||
|
||||
});
|
||||
|
||||
webBuilder.UseUrls(configuration["ApplicationUrl"]);
|
||||
|
||||
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
|
||||
"profiles": {
|
||||
"ZhiZhun.AuthenticationCenter": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"applicationUrl": "http://localhost:7200"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// 使用的是proto3版本
|
||||
syntax = "proto3";
|
||||
// 定义命名空间,后续生成代码时就会生成对应的命名空间
|
||||
option csharp_namespace = "gRPC.ZHiZHUN.AuthServer.protos";
|
||||
|
||||
/*
|
||||
每一句需要用分号结尾
|
||||
message 用来定义请求和返回数据格式
|
||||
tag message后面的值数字代表是字段的标识(tag),不是赋值,
|
||||
*/
|
||||
|
||||
|
||||
// 新增用户时需要传递数据消息, 可理解为一个类
|
||||
message GetTokenReuqest{
|
||||
string id=1;
|
||||
string userName=2;
|
||||
string realName=3;
|
||||
string reviewerCode=4;
|
||||
int32 userTypeEnumInt=5;
|
||||
string userTypeShortName=6;
|
||||
bool isAdmin=7;
|
||||
|
||||
}
|
||||
|
||||
// 新增时返回的消息格式
|
||||
message GetTokenResponse {
|
||||
int32 code=1;
|
||||
string token =2;
|
||||
}
|
||||
|
||||
|
||||
// service 用标识定义服务的,里面写对应的方法
|
||||
service TokenGrpcService{
|
||||
// 获取token
|
||||
rpc GetUserToken(GetTokenReuqest) returns (GetTokenResponse);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
// 新增用户时需要传递数据消息, 可理解为一个类
|
||||
message AddUserReuqest{
|
||||
string name=1;
|
||||
int32 age=2;
|
||||
bool isBoy=3;
|
||||
}
|
||||
// 新增时返回的消息格式
|
||||
message ResultResponse {
|
||||
int32 code=1;
|
||||
string msg =2;
|
||||
}
|
||||
//传递的查询条件信息格式,可理解为平时传入的查询条件对象
|
||||
message QueryUserReuqest{
|
||||
string name=1;
|
||||
}
|
||||
//查询返回的用户信息格式,可理解为返回的类
|
||||
message UserInfoResponse {
|
||||
string name=1;
|
||||
int32 age=2;
|
||||
string gender=3;
|
||||
}
|
||||
|
||||
// service 用标识定义服务的,里面写对应的方法
|
||||
service UserService{
|
||||
// 新增用户
|
||||
rpc AddUser(AddUserReuqest) returns (ResultResponse);
|
||||
// 查询用户
|
||||
rpc GetAllUser(QueryUserReuqest) returns (UserInfoResponse);
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,77 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using ZhiZhun.AuthenticationCenter.GrpcService;
|
||||
using ZhiZhun.AuthenticationCenter.Utility;
|
||||
using ZhiZhun.AuthenticationCenter.Utility.RSA;
|
||||
|
||||
namespace ZhiZhun.AuthenticationCenter
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
|
||||
services.AddControllers()
|
||||
.AddNewtonsoftJson();
|
||||
services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "ZHIZHUN.AuthenticationCenter", Version = "v1" });
|
||||
});
|
||||
|
||||
#region HS256 对称可逆加密
|
||||
//services.AddScoped<IJWTService, JWTHSService>();
|
||||
//services.Configure<JWTTokenOptions>(this.Configuration.GetSection("JWTTokenOptions"));
|
||||
#endregion
|
||||
|
||||
#region RS256 非对称可逆加密,需要获取一次公钥
|
||||
string keyDir = Directory.GetCurrentDirectory();
|
||||
if (RSAHelper.TryGetKeyParameters(keyDir, true, out RSAParameters keyParams) == false)
|
||||
{
|
||||
keyParams = RSAHelper.GenerateAndSaveKey(keyDir);
|
||||
}
|
||||
|
||||
services.AddScoped<IJWTService, JWTRSService>();
|
||||
services.Configure<JWTTokenOptions>(this.Configuration.GetSection("JWTTokenOptions"));
|
||||
#endregion
|
||||
|
||||
services.AddGrpc();
|
||||
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "ZHIZHUN.AuthenticationCenter v1"));
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
//app.UseAuthentication();
|
||||
//app.UseAuthorization();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
//endpoints.MapControllers();
|
||||
endpoints.MapGrpcService<GrpcTokenService>();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using ZhiZhun.AuthenticationCenter.User;
|
||||
|
||||
namespace ZhiZhun.AuthenticationCenter.Utility
|
||||
{
|
||||
public class UserBasicInfo
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
public string RealName { get; set; } = string.Empty;
|
||||
public UserType UserTypeEnum { get; set; }
|
||||
|
||||
public string ReviewerCode { get; set; } = string.Empty;
|
||||
|
||||
public string UserTypeShortName { get; set; } = string.Empty;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace ZhiZhun.AuthenticationCenter.User
|
||||
{
|
||||
public enum UserType
|
||||
{
|
||||
|
||||
//PM
|
||||
ProjectManager = 1,
|
||||
|
||||
//CRC
|
||||
ClinicalResearchCoordinator = 2,
|
||||
|
||||
//IQA
|
||||
IQC = 3,
|
||||
|
||||
|
||||
////简历管理人员
|
||||
//ResumeManager=4,
|
||||
////简历运维人员
|
||||
//ReviewerCoordinator = 5,
|
||||
|
||||
ReviewerCoordinator = 4,
|
||||
|
||||
// 大屏展示
|
||||
Dashboard = 6,
|
||||
|
||||
// 超级管理员用户类型,用于取代 SuperAdmin字段 数据库不内置这个用户类型和角色的配置,因为只允许有一个
|
||||
SuperAdmin = 8,
|
||||
|
||||
//医生用户类型暂不处理
|
||||
|
||||
ShareImage = 9,
|
||||
|
||||
Undefined = 0
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
|
||||
namespace ZhiZhun.AuthenticationCenter.Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// 简单封装个注入
|
||||
/// </summary>
|
||||
public interface IJWTService
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户信息
|
||||
/// </summary>
|
||||
/// <param name="userInfo"></param>
|
||||
/// <returns></returns>
|
||||
string GetToken(UserBasicInfo userInfo);
|
||||
|
||||
/// <summary>
|
||||
/// 获取Token+RefreshToken
|
||||
/// </summary>
|
||||
/// <param name="userInfo"></param>
|
||||
/// <returns>Token+RefreshToken</returns>
|
||||
Tuple<string, string> GetTokenWithRefresh(UserBasicInfo userInfo);
|
||||
|
||||
/// <summary>
|
||||
/// 基于refreshToken获取Token
|
||||
/// </summary>
|
||||
/// <param name="refreshToken"></param>
|
||||
/// <returns></returns>
|
||||
string GetTokenByRefresh(string refreshToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using ZhiZhun.AuthenticationCenter.User;
|
||||
|
||||
namespace ZhiZhun.AuthenticationCenter.Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// 对称可逆加密
|
||||
/// </summary>
|
||||
public class JWTHSService : IJWTService
|
||||
{
|
||||
private static Dictionary<string, UserBasicInfo> TokenCache = new Dictionary<string, UserBasicInfo>();
|
||||
|
||||
#region Option注入
|
||||
private readonly JWTTokenOptions _JWTTokenOptions;
|
||||
public JWTHSService(IOptionsMonitor<JWTTokenOptions> jwtTokenOptions)
|
||||
{
|
||||
this._JWTTokenOptions = jwtTokenOptions.CurrentValue;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public string GetToken(UserBasicInfo userModel)
|
||||
{
|
||||
return this.IssueToken(userModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新token的有效期问题上端校验
|
||||
/// </summary>
|
||||
/// <param name="refreshToken"></param>
|
||||
/// <returns></returns>
|
||||
public string GetTokenByRefresh(string refreshToken)
|
||||
{
|
||||
if (TokenCache.ContainsKey(refreshToken))
|
||||
{
|
||||
string token = this.IssueToken(TokenCache[refreshToken], 60);
|
||||
return token;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 2个token 就是有效期不一样
|
||||
/// </summary>
|
||||
/// <param name="userInfo"></param>
|
||||
/// <returns></returns>
|
||||
public Tuple<string, string> GetTokenWithRefresh(UserBasicInfo userInfo)
|
||||
{
|
||||
string token = this.IssueToken(userInfo, 60);//1分钟
|
||||
string refreshToken = this.IssueToken(userInfo, 60 * 60 * 24);//24小时
|
||||
TokenCache.Add(refreshToken, userInfo);
|
||||
|
||||
return Tuple.Create(token, refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Claims (Payload)
|
||||
Claims 部分包含了一些跟这个 token 有关的重要信息。 JWT 标准规定了一些字段,下面节选一些字段:
|
||||
iss: The issuer of the token,token 是给谁的
|
||||
sub: The subject of the token,token 主题
|
||||
exp: Expiration Time。 token 过期时间,Unix 时间戳格式
|
||||
iat: Issued At。 token 创建时间, Unix 时间戳格式
|
||||
jti: JWT ID。针对当前 token 的唯一标识
|
||||
除了规定的字段外,可以包含其他任何 JSON 兼容的字段。
|
||||
* */
|
||||
private string IssueToken(UserBasicInfo user, int second = 600)
|
||||
{
|
||||
var claims = new[]
|
||||
{
|
||||
new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
||||
new Claim("id", user.Id.ToString()),
|
||||
new Claim("name", user.UserName),
|
||||
new Claim("realName", user.RealName),
|
||||
new Claim("reviewerCode",user.ReviewerCode),
|
||||
new Claim("userTypeEnumName",user.UserTypeEnum.ToString()),
|
||||
new Claim("userTypeEnumInt",((int)user.UserTypeEnum).ToString()),
|
||||
new Claim("userTypeShortName",user.UserTypeShortName),
|
||||
new Claim("isAdmin",(user.UserTypeEnum==UserType.SuperAdmin).ToString())
|
||||
};
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this._JWTTokenOptions.SecurityKey));
|
||||
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
|
||||
var token = new JwtSecurityToken(
|
||||
issuer: this._JWTTokenOptions.Issuer,
|
||||
audience: this._JWTTokenOptions.Audience,
|
||||
claims: claims,
|
||||
expires: DateTime.Now.AddSeconds(second),//10分钟有效期
|
||||
notBefore: null,//立即生效 DateTime.Now.AddMilliseconds(30),//30s后有效
|
||||
signingCredentials: creds);
|
||||
string returnToken = new JwtSecurityTokenHandler().WriteToken(token);
|
||||
return returnToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace ZhiZhun.AuthenticationCenter.Utility
|
||||
{
|
||||
public class JWTTokenDeserialize
|
||||
{
|
||||
public static string AnalysisToken(string token)
|
||||
{
|
||||
string info = token.Split('.')[1];
|
||||
string escapeInfo = Escape(info);
|
||||
string sInfo = FromBase64(escapeInfo);
|
||||
Newtonsoft.Json.JsonConvert.DeserializeObject(sInfo);
|
||||
return sInfo;
|
||||
}
|
||||
|
||||
public static string ToBase64(string content)
|
||||
{
|
||||
byte[] byteContent = System.Text.Encoding.Default.GetBytes(content);
|
||||
return Convert.ToBase64String(byteContent);
|
||||
}
|
||||
|
||||
public static string FromBase64(string result)
|
||||
{
|
||||
byte[] byteResult = Convert.FromBase64String(result);
|
||||
return System.Text.Encoding.Default.GetString(byteResult);
|
||||
}
|
||||
|
||||
public static string Escape(string str)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (char c in str)
|
||||
{
|
||||
sb.Append((Char.IsLetterOrDigit(c)
|
||||
|| c == '-' || c == '_' || c == '\\'
|
||||
|| c == '/' || c == '.') ? c.ToString() : Uri.HexEscape(c));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string UnEscape(string str)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int len = str.Length;
|
||||
int i = 0;
|
||||
while (i != len)
|
||||
{
|
||||
if (Uri.IsHexEncoding(str, i))
|
||||
sb.Append(Uri.HexUnescape(str, ref i));
|
||||
else
|
||||
sb.Append(str[i++]);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace ZhiZhun.AuthenticationCenter.Utility
|
||||
{
|
||||
public class JWTTokenOptions
|
||||
{
|
||||
public string Audience
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string SecurityKey
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public string Issuer
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.IO;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using ZhiZhun.AuthenticationCenter.User;
|
||||
using ZhiZhun.AuthenticationCenter.Utility.RSA;
|
||||
|
||||
namespace ZhiZhun.AuthenticationCenter.Utility
|
||||
{
|
||||
|
||||
public class JWTRSService : IJWTService
|
||||
{
|
||||
private static Dictionary<string, UserBasicInfo> TokenCache = new Dictionary<string, UserBasicInfo>();
|
||||
|
||||
#region Option注入
|
||||
private readonly JWTTokenOptions _JWTTokenOptions;
|
||||
public JWTRSService(IOptionsMonitor<JWTTokenOptions> jwtTokenOptions)
|
||||
{
|
||||
this._JWTTokenOptions = jwtTokenOptions.CurrentValue;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public string GetToken(UserBasicInfo userModel)
|
||||
{
|
||||
return this.IssueToken(userModel);
|
||||
}
|
||||
|
||||
|
||||
private string IssueToken(UserBasicInfo user, int second = 600*6)
|
||||
{
|
||||
|
||||
var claims = new[]
|
||||
{
|
||||
//new Claim(ClaimTypes.Name, userModel.Name),
|
||||
//new Claim("EMail", userModel.EMail),
|
||||
//new Claim("Account", userModel.Account),
|
||||
//new Claim("Age", userModel.Age.ToString()),
|
||||
//new Claim("Id", userModel.Id.ToString()),
|
||||
//new Claim("Mobile", userModel.Mobile),
|
||||
//new Claim("Sex", userModel.Sex.ToString())//各种信息拼装
|
||||
//new Claim(ClaimTypes.Role,userModel.Role),
|
||||
//new Claim("Role", userModel.Role),//这个不能角色授权
|
||||
|
||||
new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
||||
new Claim("id", user.Id.ToString()),
|
||||
new Claim("name", user.UserName),
|
||||
new Claim("realName", user.RealName),
|
||||
new Claim("reviewerCode",user.ReviewerCode),
|
||||
new Claim("userTypeEnumName",user.UserTypeEnum.ToString()),
|
||||
new Claim("userTypeEnumInt",((int)user.UserTypeEnum).ToString()),
|
||||
new Claim("userTypeShortName",user.UserTypeShortName),
|
||||
new Claim("isAdmin",(user.UserTypeEnum==UserType.SuperAdmin).ToString())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
string keyDir = Directory.GetCurrentDirectory();
|
||||
if (RSAHelper.TryGetKeyParameters(keyDir, true, out RSAParameters keyParams) == false)
|
||||
{
|
||||
keyParams = RSAHelper.GenerateAndSaveKey(keyDir);
|
||||
}
|
||||
var credentials = new SigningCredentials(new RsaSecurityKey(keyParams), SecurityAlgorithms.RsaSha256Signature);
|
||||
|
||||
var token = new JwtSecurityToken(
|
||||
issuer: this._JWTTokenOptions.Issuer,
|
||||
audience: this._JWTTokenOptions.Audience,
|
||||
claims: claims,
|
||||
expires: DateTime.Now.AddSeconds(second),//默认10分钟有效期
|
||||
notBefore: DateTime.Now.AddMilliseconds(30),
|
||||
signingCredentials: credentials);
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
string tokenString = handler.WriteToken(token);
|
||||
return tokenString;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 刷新token的有效期问题上端校验
|
||||
/// </summary>
|
||||
/// <param name="refreshToken"></param>
|
||||
/// <returns></returns>
|
||||
public string GetTokenByRefresh(string refreshToken)
|
||||
{
|
||||
if (TokenCache.ContainsKey(refreshToken))
|
||||
{
|
||||
string token = this.IssueToken(TokenCache[refreshToken], 60);
|
||||
return token;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public Tuple<string, string> GetTokenWithRefresh(UserBasicInfo userInfo)
|
||||
{
|
||||
string token = this.IssueToken(userInfo, 60);//1分钟
|
||||
string refreshToken = this.IssueToken(userInfo, 60 * 60 * 24);//24小时
|
||||
TokenCache.Add(refreshToken, userInfo);
|
||||
|
||||
return Tuple.Create(token, refreshToken);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ZhiZhun.AuthenticationCenter.Utility.RSA
|
||||
{
|
||||
public class RSAHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 从本地文件中读取用来签发 Token 的 RSA Key
|
||||
/// </summary>
|
||||
/// <param name="filePath">存放密钥的文件夹路径</param>
|
||||
/// <param name="withPrivate"></param>
|
||||
/// <param name="keyParameters"></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryGetKeyParameters(string filePath, bool withPrivate, out RSAParameters keyParameters)
|
||||
{
|
||||
string filename = withPrivate ? "key.json" : "key.public.json";
|
||||
string fileTotalPath = Path.Combine(filePath, filename);
|
||||
keyParameters = default(RSAParameters);
|
||||
if (!File.Exists(fileTotalPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyParameters = JsonConvert.DeserializeObject<RSAParameters>(File.ReadAllText(fileTotalPath));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 生成并保存 RSA 公钥与私钥
|
||||
/// <param name="filePath">存放密钥的文件夹路径</param>
|
||||
/// <param name="withPrivate"></param>
|
||||
/// <returns></returns>
|
||||
public static RSAParameters GenerateAndSaveKey(string filePath, bool withPrivate = true)
|
||||
{
|
||||
RSAParameters publicKeys, privateKeys;
|
||||
using (var rsa = new RSACryptoServiceProvider(2048))//即时生成
|
||||
{
|
||||
try
|
||||
{
|
||||
privateKeys = rsa.ExportParameters(true);
|
||||
publicKeys = rsa.ExportParameters(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
rsa.PersistKeyInCsp = false;
|
||||
}
|
||||
}
|
||||
File.WriteAllText(Path.Combine(filePath, "key.json"), JsonConvert.SerializeObject(privateKeys));
|
||||
File.WriteAllText(Path.Combine(filePath, "key.public.json"), JsonConvert.SerializeObject(publicKeys));
|
||||
return withPrivate ? privateKeys : publicKeys;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>ZhiZhun.AuthenticationCenter</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="M:Zhaoxi.NET6.AuthenticationCenter.Controllers.JWTController.Login(System.String,System.String)">
|
||||
<summary>
|
||||
数据库校验
|
||||
</summary>
|
||||
<param name="name"></param>
|
||||
<param name="password"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:Zhaoxi.NET6.AuthenticationCenter.Controllers.JWTController.LoginWithRefresh(System.String,System.String)">
|
||||
<summary>
|
||||
生成Token+RefreshToken
|
||||
</summary>
|
||||
<param name="name"></param>
|
||||
<param name="password"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:ZhiZhun.AuthenticationCenter.Utility.IJWTService">
|
||||
<summary>
|
||||
简单封装个注入
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ZhiZhun.AuthenticationCenter.Utility.IJWTService.GetToken(ZhiZhun.AuthenticationCenter.Utility.UserBasicInfo)">
|
||||
<summary>
|
||||
用户信息
|
||||
</summary>
|
||||
<param name="userInfo"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ZhiZhun.AuthenticationCenter.Utility.IJWTService.GetTokenWithRefresh(ZhiZhun.AuthenticationCenter.Utility.UserBasicInfo)">
|
||||
<summary>
|
||||
获取Token+RefreshToken
|
||||
</summary>
|
||||
<param name="userInfo"></param>
|
||||
<returns>Token+RefreshToken</returns>
|
||||
</member>
|
||||
<member name="M:ZhiZhun.AuthenticationCenter.Utility.IJWTService.GetTokenByRefresh(System.String)">
|
||||
<summary>
|
||||
基于refreshToken获取Token
|
||||
</summary>
|
||||
<param name="refreshToken"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:ZhiZhun.AuthenticationCenter.Utility.JWTHSService">
|
||||
<summary>
|
||||
对称可逆加密
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:ZhiZhun.AuthenticationCenter.Utility.JWTHSService.GetTokenByRefresh(System.String)">
|
||||
<summary>
|
||||
刷新token的有效期问题上端校验
|
||||
</summary>
|
||||
<param name="refreshToken"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ZhiZhun.AuthenticationCenter.Utility.JWTHSService.GetTokenWithRefresh(ZhiZhun.AuthenticationCenter.Utility.UserBasicInfo)">
|
||||
<summary>
|
||||
2个token 就是有效期不一样
|
||||
</summary>
|
||||
<param name="userInfo"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ZhiZhun.AuthenticationCenter.Utility.JWTRSService.GetTokenByRefresh(System.String)">
|
||||
<summary>
|
||||
刷新token的有效期问题上端校验
|
||||
</summary>
|
||||
<param name="refreshToken"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ZhiZhun.AuthenticationCenter.Utility.RSA.RSAHelper.TryGetKeyParameters(System.String,System.Boolean,System.Security.Cryptography.RSAParameters@)">
|
||||
<summary>
|
||||
从本地文件中读取用来签发 Token 的 RSA Key
|
||||
</summary>
|
||||
<param name="filePath">存放密钥的文件夹路径</param>
|
||||
<param name="withPrivate"></param>
|
||||
<param name="keyParameters"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:ZhiZhun.AuthenticationCenter.Utility.RSA.RSAHelper.GenerateAndSaveKey(System.String,System.Boolean)">
|
||||
<summary>
|
||||
生成并保存 RSA 公钥与私钥
|
||||
</summary>
|
||||
<param name="filePath">存放密钥的文件夹路径</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.GrpcTokenReflection">
|
||||
<summary>Holder for reflection information generated from Protos/GrpcToken.proto</summary>
|
||||
</member>
|
||||
<member name="P:gRPC.ZHiZHUN.AuthServer.protos.GrpcTokenReflection.Descriptor">
|
||||
<summary>File descriptor for Protos/GrpcToken.proto</summary>
|
||||
</member>
|
||||
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest">
|
||||
<summary>
|
||||
新增用户时需要传递数据消息, 可理解为一个类
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.IdFieldNumber">
|
||||
<summary>Field number for the "id" field.</summary>
|
||||
</member>
|
||||
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.UserNameFieldNumber">
|
||||
<summary>Field number for the "userName" field.</summary>
|
||||
</member>
|
||||
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.RealNameFieldNumber">
|
||||
<summary>Field number for the "realName" field.</summary>
|
||||
</member>
|
||||
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.ReviewerCodeFieldNumber">
|
||||
<summary>Field number for the "reviewerCode" field.</summary>
|
||||
</member>
|
||||
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.UserTypeEnumIntFieldNumber">
|
||||
<summary>Field number for the "userTypeEnumInt" field.</summary>
|
||||
</member>
|
||||
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.UserTypeShortNameFieldNumber">
|
||||
<summary>Field number for the "userTypeShortName" field.</summary>
|
||||
</member>
|
||||
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest.IsAdminFieldNumber">
|
||||
<summary>Field number for the "isAdmin" field.</summary>
|
||||
</member>
|
||||
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.GetTokenResponse">
|
||||
<summary>
|
||||
新增时返回的消息格式
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenResponse.CodeFieldNumber">
|
||||
<summary>Field number for the "code" field.</summary>
|
||||
</member>
|
||||
<member name="F:gRPC.ZHiZHUN.AuthServer.protos.GetTokenResponse.TokenFieldNumber">
|
||||
<summary>Field number for the "token" field.</summary>
|
||||
</member>
|
||||
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService">
|
||||
<summary>
|
||||
service 用标识定义服务的,里面写对应的方法
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.Descriptor">
|
||||
<summary>Service descriptor</summary>
|
||||
</member>
|
||||
<member name="T:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceBase">
|
||||
<summary>Base class for server-side implementations of TokenGrpcService</summary>
|
||||
</member>
|
||||
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceBase.GetUserToken(gRPC.ZHiZHUN.AuthServer.protos.GetTokenReuqest,Grpc.Core.ServerCallContext)">
|
||||
<summary>
|
||||
获取token
|
||||
</summary>
|
||||
<param name="request">The request received from the client.</param>
|
||||
<param name="context">The context of the server-side call handler being invoked.</param>
|
||||
<returns>The response to send back to the client (wrapped by a task).</returns>
|
||||
</member>
|
||||
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.BindService(gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceBase)">
|
||||
<summary>Creates service definition that can be registered with a server</summary>
|
||||
<param name="serviceImpl">An object implementing the server-side handling logic.</param>
|
||||
</member>
|
||||
<member name="M:gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.BindService(Grpc.Core.ServiceBinderBase,gRPC.ZHiZHUN.AuthServer.protos.TokenGrpcService.TokenGrpcServiceBase)">
|
||||
<summary>Register service method with a service binder with or without implementation. Useful when customizing the service binding logic.
|
||||
Note: this method is part of an experimental API that can change or be removed without any prior notice.</summary>
|
||||
<param name="serviceBinder">Service methods will be bound by calling <c>AddMethod</c> on this object.</param>
|
||||
<param name="serviceImpl">An object implementing the server-side handling logic.</param>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ApplicationUrl": "http://localhost:7000",
|
||||
"AllowedHosts": "*",
|
||||
"JWTTokenOptions": {
|
||||
"Audience": "IRaCIS",
|
||||
"Issuer": "ZhiZhun",
|
||||
"SecurityKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"D":"bmUaN4NbU6fINHpR/DhZEStGnIMF5zJC393MY7TWYYIqPMJLacer7cky58yvXr1Ar4Q7RGkppPO/yzOUD72yzkZfMpVKdfvIusXfoMz2+u2j4IwIgWRAJ+bI/dB91glMMFsMBzLvasKYCKw0UeoayhIQ+WLWqTWldnTafZqtcgne7MuHTiLNBKh1uynZ/A0y3U4BVjy6FW/WZS6U5ajoDiicWxAjW9YfJ1OQbtdX0wJAos+MrES7wHdCSwuvUj7PubAoXXJEbMy5ilO/Uc/mmJoI6ZzqzL9bslBa/WixVgQzHqd46AoJIaXbni+Ei2wIwqdlZCg6J5XW5RDAx1Xk1Q==","DP":"YinAjBjQ9hQRYwmOdx+8EKF14WxMgSG3y8By5AhR2UZ22WRFjwjsD4g0abGyP6HkrwHJ+40R1P4t1OXW7yGqlzHisDeGFbxnlJLk6y9G1YLVAfdCTQgclgodztml63uB/saNhjN5TP8HfGUi6MRQr8GGmV78RpyjtvZmEobdwYs=","DQ":"drfBawNB1IwWN233uCSELtWapNQ6cjx54kY4ktKuF5RiwwNli6ydDUrbwOw7gKUPDr+hf7Mb2N+Y3M++wtw4ocEtotG0xMwwtkHRDCQC7EWV4hiN3fnVOWnV09j3GNMd9pQdp0NM2K6ZwZg82uFRtdC8Wx1B7y3rgmGqTvvD3ms=","Exponent":"AQAB","InverseQ":"j8vUuCnKnHd6QAkRzS+KDNSyoK4QDviHSayJMhV5IeqdgPH2/rOWmRrJbxMze3cnCz1V0O9OO3KK+jzY1W1EhNx5gcgr1VO748YcSCyEOg4Anj90cIPtFrCLad5qLm3pE3ZIztM+QjPlOXEehggeLQOjs7X3ehx0HO90xMrw/9Q=","Modulus":"uPdYYOZKfIqyUkjizqJ9Xn1U4M/GKJDWQ749TviZMJ/6wdJAwTkJOy3PxXXpjCyUViK4ATu1ZzAdoMTc5VC1IkG01SeEj2ynqx4q6YJnXjC5i+GqSRWP6ijbx0eDRcgVKeNm1xGM927UD1ezSFetxbD/erhrd0tNZ/QEIFATdLPd/D60RoiF8hYCc2lC61z1pKs7ZyAEckV8YaMSZAGOO/sGw1aka55aVpZ6kQmQ7sD6f27N9hOCzV6t+jxEBdANNu/wEb2Dhbvz1ap/lMrk0h+vQaTwFvudJRFifn2uvNl25NFjxz0ag+JRVnnsoXBI3PtW+1xBtvHxPCGU+tYSHQ==","P":"9Bos1g9+XzjUIn3/wQny0AUxJjl26swq/Ka1tLZmQpRdmSAN3TrxTs70s8J0XI1Gz4Y9p7HguRngCJVkdP7cXpNVaXszGH4YKEbiZ1WbAaNqa2A8CEyi0dGqPSumfbnw43UPhRNGyXsukh3uKj8ODmDJ/eXZBoHahXcHp04g7s8=","Q":"wftKXmCmnD7mKp/NYvoCQVtGOwgr5wzFuabNVcvvwGTcMjTjzVX8F97RLqM7RKLBLL12gGi/mxMdPcf4grweI3Xm6pUIACjIH4VL22VoQv6+XZjrsALhPMaLmS5mtSPHkCOQvAMdi4OOAgRRSIOP4+6grL/KkU414kb95DkuS1M="}
|
||||
@@ -0,0 +1 @@
|
||||
{"D":null,"DP":null,"DQ":null,"Exponent":"AQAB","InverseQ":null,"Modulus":"uPdYYOZKfIqyUkjizqJ9Xn1U4M/GKJDWQ749TviZMJ/6wdJAwTkJOy3PxXXpjCyUViK4ATu1ZzAdoMTc5VC1IkG01SeEj2ynqx4q6YJnXjC5i+GqSRWP6ijbx0eDRcgVKeNm1xGM927UD1ezSFetxbD/erhrd0tNZ/QEIFATdLPd/D60RoiF8hYCc2lC61z1pKs7ZyAEckV8YaMSZAGOO/sGw1aka55aVpZ6kQmQ7sD6f27N9hOCzV6t+jxEBdANNu/wEb2Dhbvz1ap/lMrk0h+vQaTwFvudJRFifn2uvNl25NFjxz0ag+JRVnnsoXBI3PtW+1xBtvHxPCGU+tYSHQ==","P":null,"Q":null}
|
||||
Reference in New Issue
Block a user