489 lines
24 KiB
C#
489 lines
24 KiB
C#
using Azure.Core;
|
||
using CloudBuilder.Core.Authorization;
|
||
using CloudBuilder.Core.DatabaseAccessor;
|
||
using CloudBuilder.Core.DatabaseAccessor.Entity;
|
||
using CloudBuilder.Core.DependencyInjection.EventBuses;
|
||
using CloudBuilder.Core.DependencyInjection.Request;
|
||
using CloudBuilder.Core.Policy;
|
||
using CloudBuilder.Core.Service;
|
||
using CloudBuilder.Security.Data;
|
||
using CloudBuilder.Security.Entity;
|
||
using CloudBuilder.Security.Policy;
|
||
using CloudBuilder.Security.Publisher;
|
||
using CloudBuilder.Security.Service.Authorization;
|
||
using CloudBuilder.Security.Service.Publisher;
|
||
using DocumentFormat.OpenXml.Spreadsheet;
|
||
using Microsoft.AspNetCore.Authorization;
|
||
using Microsoft.AspNetCore.Http;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
using Microsoft.IdentityModel.JsonWebTokens;
|
||
using Microsoft.IdentityModel.Tokens;
|
||
using System.IdentityModel.Tokens.Jwt;
|
||
using System.Runtime;
|
||
using System.Text;
|
||
using System.Text.RegularExpressions;
|
||
|
||
namespace CloudBuilder.Security.Service
|
||
{
|
||
public class AuthService : IAuthService
|
||
{
|
||
private readonly IApplicationService service;
|
||
private readonly IHttpContextAccessor httpContextAccessor;
|
||
private readonly ILocaleMessageManager localeMessageManager;
|
||
private readonly IContext context;
|
||
private IRepository<SecurityUserEntity> repository;
|
||
public AuthService(IApplicationService service, IHttpContextAccessor httpContextAccessor, ILocaleMessageManager localeMessageManager, IContext context)
|
||
{
|
||
this.service = service;
|
||
this.httpContextAccessor = httpContextAccessor;
|
||
this.localeMessageManager = localeMessageManager;
|
||
this.context = context;
|
||
repository = service.GetRepository<IRepository<SecurityUserEntity>>();
|
||
}
|
||
|
||
[AllowAnonymous]
|
||
[UnitOfWork]
|
||
public LoginProfile Login(LoginData data)
|
||
{
|
||
context.SetCulture(data.Culture);
|
||
string certification = localeMessageManager.ComposeMessage(typeof(AuthService).Name, "certification");
|
||
SecurityUserEntity securityUserEntity = repository.DetachedEntities.Where(x =>
|
||
(x.UserName == data.UserMobile || x.UserMobile == data.UserMobile)
|
||
&& x.UserIsValidIndc == YesNoPolicy.YES).FirstOrDefault()!;
|
||
|
||
if (securityUserEntity == null)
|
||
{
|
||
throw new ValidatedException(certification);
|
||
}
|
||
|
||
var descKey = service.Configuration[SecuritySettingsPolicy.SecuritySettings_DescKey];
|
||
|
||
var privateKey = service.Configuration[SecuritySettingsPolicy.SecuritySettings_RsaPrivateKey];
|
||
var rsa = new RSA(privateKey, true);
|
||
|
||
var psd = rsa.DecodeOrNull(data.RsaUserPassword);
|
||
if (string.IsNullOrEmpty(psd)) throw new ValidatedException(certification);
|
||
//052636a8-b146-9efd-f5dc-0034a3c5bb34+password
|
||
var guid = psd.Substring(0, 36);
|
||
|
||
|
||
if (guid != data.Guid)
|
||
{
|
||
throw new ValidatedException(certification);
|
||
}
|
||
|
||
if (securityUserEntity.IsAccountsLockedIndc == YesNoPolicy.YES && securityUserEntity.AccountsLockedDatetime.HasValue
|
||
&& securityUserEntity.AccountsLockedDatetime.Value.Subtract(DateTime.Now).TotalMinutes > 0)
|
||
{
|
||
throw new ValidatedException(localeMessageManager.ComposeMessage("AuthService", "locked"));
|
||
}
|
||
|
||
data.UserPassword = psd.Substring(36, psd.Length - 36);
|
||
|
||
if (securityUserEntity.UserPassword != data.UserPassword)
|
||
{
|
||
securityUserEntity.ErrorLoginCount += 1;
|
||
//输错多少次后,账号锁定
|
||
if (securityUserEntity.ErrorLoginCount > SecurityUserPolicy.ERROR_LOGIN_COUNT)
|
||
{
|
||
securityUserEntity.IsAccountsLockedIndc = YesNoPolicy.YES;
|
||
securityUserEntity.AccountsLockedDatetime = DateTime.Now.AddDays(1);
|
||
}
|
||
|
||
repository.UpdateNow(securityUserEntity);
|
||
|
||
throw new ValidatedException(certification);
|
||
}
|
||
|
||
JwtGenerate jwtGenerate = service.ServiceProvider.GetService<JwtGenerate>()!;
|
||
|
||
string clainmName = Guid.NewGuid().ToString();
|
||
Dictionary<string, string> claims = new Dictionary<string, string>();
|
||
claims.Add(ClaimPolicy.CLAINM_NAME, clainmName);
|
||
claims.Add(ClaimPolicy.CLAINM_ACCOUNT, securityUserEntity.UserMobile!);
|
||
claims.Add(ClaimPolicy.CLAINM_USERID, securityUserEntity.UserName);
|
||
claims.Add(ClaimPolicy.CLAINM_LOCALE, data.Culture);
|
||
|
||
var accessToken = jwtGenerate.Generate(claims);
|
||
if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey("Authorization"))
|
||
httpContextAccessor.HttpContext.Request.Headers.Remove("Authorization");
|
||
httpContextAccessor.HttpContext.Request.Headers.Add("Authorization", "Bearer " + accessToken);
|
||
|
||
if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey(ClaimPolicy.HEADER_LOCALE))
|
||
httpContextAccessor.HttpContext.Request.Headers.Remove(ClaimPolicy.HEADER_LOCALE);
|
||
httpContextAccessor.HttpContext.Request.Headers.Add(ClaimPolicy.HEADER_LOCALE, data.Culture);
|
||
|
||
service.UserId = securityUserEntity.UserName;
|
||
|
||
securityUserEntity.ErrorLoginCount = 0;
|
||
securityUserEntity.IsAccountsLockedIndc = YesNoPolicy.NO;
|
||
securityUserEntity.AccountsLockedDatetime = null;
|
||
//更新最后登录日期
|
||
securityUserEntity.LastLoginDatetime = DateTime.Now;
|
||
|
||
repository.UpdateNow(securityUserEntity);
|
||
|
||
IRepository<SecurityUserWebLoginEntity> repositoryLog = service.GetRepository<IRepository<SecurityUserWebLoginEntity>>();
|
||
|
||
SecurityUserWebLoginEntity webLogin = new SecurityUserWebLoginEntity
|
||
{
|
||
Username = securityUserEntity.UserName,
|
||
SessionId = clainmName,
|
||
LoginTime = DateTime.Now,
|
||
HostIp = httpContextAccessor.HttpContext.Connection.RemoteIpAddress?.MapToIPv4()?.ToString(),
|
||
HostUserAgent = this.httpContextAccessor?.HttpContext?.Request.Headers.UserAgent.ToString(),
|
||
RefreshToken = jwtGenerate.GenerateRefreshToken(),
|
||
RefreshTokenRefreshedTime = DateTime.Now,
|
||
};
|
||
|
||
repositoryLog.InsertNow(webLogin);
|
||
PermissionContext permissionContext = new PermissionContext(service);
|
||
return new LoginProfile
|
||
{
|
||
Token = new JwtInfo() { AccessToken = accessToken, RefreshToken = webLogin.RefreshToken, CreatedTime = webLogin.RefreshTokenRefreshedTime },
|
||
Username = securityUserEntity.UserName,
|
||
UserType = securityUserEntity.UserType,
|
||
UserLocalName = securityUserEntity.UserLocalName,
|
||
UserEngName = securityUserEntity.UserEngName,
|
||
UserMobile = securityUserEntity.UserMobile!,
|
||
PermissionInfo = permissionContext.GetUserPermissionInfo()
|
||
};
|
||
}
|
||
|
||
[PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: "LoginAgent")]
|
||
[UnitOfWork]
|
||
public LoginProfile LoginAgent(LoginData data)
|
||
{
|
||
LoginProfile loginProfile = Login(data);
|
||
|
||
SecurityUserEntity agent = repository.DetachedEntities.Where(x =>
|
||
(x.UserMobile == data.AgentUserName && x.UserIsValidIndc == YesNoPolicy.YES)).FirstOrDefault()!;
|
||
|
||
if (agent == null)
|
||
{
|
||
throw new ValidatedException("代理用户不存在.");
|
||
}
|
||
|
||
JwtGenerate jwtGenerate = service.ServiceProvider.GetService<JwtGenerate>()!;
|
||
|
||
Dictionary<string, string> claims = new Dictionary<string, string>();
|
||
claims.Add(ClaimPolicy.CLAINM_NAME, agent.UserName);
|
||
claims.Add(ClaimPolicy.CLAINM_ACCOUNT, agent.UserMobile!);
|
||
claims.Add(ClaimPolicy.CLAINM_USERID, agent.UserName);
|
||
claims.Add(ClaimPolicy.CLAINM_LOCALE, data.Culture);
|
||
|
||
var accessToken = jwtGenerate.Generate(claims);
|
||
if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey("Authorization"))
|
||
httpContextAccessor.HttpContext.Request.Headers.Remove("Authorization");
|
||
httpContextAccessor.HttpContext.Request.Headers.Add("Authorization", "Bearer " + accessToken);
|
||
|
||
if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey(ClaimPolicy.HEADER_LOCALE))
|
||
httpContextAccessor.HttpContext.Request.Headers.Remove(ClaimPolicy.HEADER_LOCALE);
|
||
httpContextAccessor.HttpContext.Request.Headers.Add(ClaimPolicy.HEADER_LOCALE, data.Culture);
|
||
|
||
SecurityUserWebLoginEntity webLogin = new SecurityUserWebLoginEntity
|
||
{
|
||
Username = agent.UserName,
|
||
SessionId = Guid.NewGuid().ToString(),
|
||
LoginTime = DateTime.Now,
|
||
HostIp = loginProfile.Username,
|
||
HostUserAgent = loginProfile.UserMobile!,
|
||
RefreshToken = jwtGenerate.GenerateRefreshToken(),
|
||
RefreshTokenRefreshedTime = DateTime.Now,
|
||
};
|
||
|
||
IRepository<SecurityUserWebLoginEntity> repositoryLog = service.GetRepository<IRepository<SecurityUserWebLoginEntity>>();
|
||
|
||
repositoryLog.InsertNow(webLogin);
|
||
|
||
service.UserId = agent.UserName;
|
||
PermissionContext permissionContext = new PermissionContext(service);
|
||
return new LoginProfile
|
||
{
|
||
Token = new JwtInfo() { AccessToken = accessToken, RefreshToken = webLogin.RefreshToken, CreatedTime = webLogin.RefreshTokenRefreshedTime },
|
||
Username = agent.UserName,
|
||
UserType = agent.UserType,
|
||
UserLocalName = agent.UserLocalName,
|
||
UserEngName = agent.UserEngName,
|
||
UserMobile = agent.UserMobile!,
|
||
PermissionInfo = permissionContext.GetUserPermissionInfo()
|
||
};
|
||
}
|
||
|
||
[AllowAnonymous]
|
||
[UnitOfWork]
|
||
public string Register(RegisterData data)
|
||
{
|
||
SecurityUserEntity securityUser = repository.DetachedEntities.Where(x => x.UserMobile == data.UserMobile).FirstOrDefault()!;
|
||
if (securityUser != null)
|
||
{
|
||
throw new ValidatedException("手机号已注册.");
|
||
}
|
||
|
||
securityUser = new SecurityUserEntity();
|
||
|
||
if (string.IsNullOrEmpty(data.UserMobile) || string.IsNullOrEmpty(data.RsaUserPassword)) return null;
|
||
|
||
ISecurityGeneratorNumberService securityGeneratorNumberService = service.ServiceProvider.GetService<ISecurityGeneratorNumberService>()!;
|
||
string userName = securityGeneratorNumberService.GetNo(SecurityPrefixPolicy.SECURITY_USER, SecurityPrefixPolicy.SECURITY_USER_USER_NAME, null, YesNoPolicy.NO, SecurityPrefixPolicy.SECURITY_USER_FORMAT);
|
||
|
||
var privateKey = service.Configuration[SecuritySettingsPolicy.SecuritySettings_RsaPrivateKey];
|
||
var rsa = new System.RSA(privateKey, true);
|
||
|
||
securityUser.UserPassword = rsa.DecodeOrNull(data.RsaUserPassword);
|
||
//052636a8-b146-9efd-f5dc-0034a3c5bb34+password(MD5)
|
||
string guid = securityUser.UserPassword.Substring(0, 36);
|
||
|
||
securityUser.UserPassword = securityUser.UserPassword.Substring(36, securityUser.UserPassword.Length - 36);
|
||
securityUser.UserName = userName;
|
||
securityUser.UserMobile = data.UserMobile;
|
||
securityUser.UserLocalName = "用户" + securityUser.UserName;
|
||
securityUser.UserIsValidIndc = YesNoPolicy.YES;
|
||
|
||
JwtGenerate jwtGenerate = service.ServiceProvider.GetService<JwtGenerate>()!;
|
||
|
||
Dictionary<string, string> claims = new Dictionary<string, string>();
|
||
claims.Add(ClaimPolicy.CLAINM_NAME, securityUser.UserName);
|
||
claims.Add(ClaimPolicy.CLAINM_ACCOUNT, securityUser.UserName);
|
||
claims.Add(ClaimPolicy.CLAINM_USERID, securityUser.UserName);
|
||
claims.Add(ClaimPolicy.CLAINM_LOCALE, CulturePolicy.ZH_CN);
|
||
|
||
service.UserId = securityUser.UserName;
|
||
|
||
var accessToken = jwtGenerate.Generate(claims);
|
||
if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey("Authorization"))
|
||
httpContextAccessor.HttpContext.Request.Headers.Remove("Authorization");
|
||
httpContextAccessor.HttpContext.Request.Headers.Add("Authorization", "Bearer " + accessToken);
|
||
|
||
repository.InsertNow(securityUser);
|
||
|
||
//发布注册的事务
|
||
EventData eventData = new EventData();
|
||
ISecurityUserRegisterPublisher publisher = service.ServiceProvider.GetService<ISecurityUserRegisterPublisher>()!;
|
||
eventData.EventSource = securityUser;
|
||
eventData.EventId = typeof(SecurityUserRegisterPublisher).Name;
|
||
publisher.Publish(eventData);
|
||
|
||
return securityUser.UserMobile;
|
||
}
|
||
|
||
[PermissionOperate(name: SecurityPermissionPolicy.SecurityUser, operate: Operate.Update)]
|
||
[UnitOfWork]
|
||
public LoginProfile AmendPassword(LoginData data)
|
||
{
|
||
SecurityUserEntity securityUserEntity = repository.DetachedEntities.Where(x =>
|
||
x.UserName == service.UserId
|
||
&& x.UserIsValidIndc == YesNoPolicy.YES).FirstOrDefault()!;
|
||
|
||
if (securityUserEntity == null)
|
||
{
|
||
throw new ValidatedException("认证不通过.");
|
||
}
|
||
|
||
var descKey = service.Configuration[SecuritySettingsPolicy.SecuritySettings_DescKey];
|
||
|
||
var privateKey = service.Configuration[SecuritySettingsPolicy.SecuritySettings_RsaPrivateKey];
|
||
var rsa = new RSA(privateKey, true);
|
||
|
||
var psd = rsa.DecodeOrNull(data.RsaUserPassword);
|
||
if (string.IsNullOrEmpty(psd)) throw new ValidatedException("认证不通过.");
|
||
//052636a8-b146-9efd-f5dc-0034a3c5bb34+password
|
||
var guid = psd.Substring(0, 36);
|
||
|
||
|
||
if (guid != data.UserName)
|
||
{
|
||
throw new ValidatedException("认证不通过.");
|
||
}
|
||
|
||
if (securityUserEntity.IsAccountsLockedIndc == YesNoPolicy.YES && securityUserEntity.AccountsLockedDatetime.HasValue
|
||
&& securityUserEntity.AccountsLockedDatetime.Value.Subtract(DateTime.Now).TotalMinutes > 0)
|
||
{
|
||
throw new ValidatedException("用户账号已锁定.");
|
||
}
|
||
|
||
if (securityUserEntity.UserPassword != psd.Substring(36, psd.Length - 36))
|
||
{
|
||
securityUserEntity.ErrorLoginCount += 1;
|
||
//输错多少次后,账号锁定
|
||
if (securityUserEntity.ErrorLoginCount > SecurityUserPolicy.ERROR_LOGIN_COUNT)
|
||
{
|
||
securityUserEntity.IsAccountsLockedIndc = YesNoPolicy.YES;
|
||
securityUserEntity.AccountsLockedDatetime = DateTime.Now.AddDays(1);
|
||
}
|
||
|
||
repository.UpdateNow(securityUserEntity);
|
||
|
||
throw new ValidatedException("认证不通过.");
|
||
}
|
||
|
||
JwtGenerate jwtGenerate = service.ServiceProvider.GetService<JwtGenerate>()!;
|
||
|
||
string clainmName = Guid.NewGuid().ToString();
|
||
Dictionary<string, string> claims = new Dictionary<string, string>();
|
||
claims.Add(ClaimPolicy.CLAINM_NAME, clainmName);
|
||
claims.Add(ClaimPolicy.CLAINM_ACCOUNT, securityUserEntity.UserMobile!);
|
||
claims.Add(ClaimPolicy.CLAINM_USERID, securityUserEntity.UserName);
|
||
claims.Add(ClaimPolicy.CLAINM_LOCALE, data.Culture ?? CulturePolicy.ZH_CN);
|
||
|
||
var accessToken = jwtGenerate.Generate(claims);
|
||
if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey("Authorization"))
|
||
httpContextAccessor.HttpContext.Request.Headers.Remove("Authorization");
|
||
httpContextAccessor.HttpContext.Request.Headers.Add("Authorization", "Bearer " + accessToken);
|
||
|
||
securityUserEntity.ErrorLoginCount = 0;
|
||
securityUserEntity.IsAccountsLockedIndc = YesNoPolicy.NO;
|
||
securityUserEntity.AccountsLockedDatetime = null;
|
||
//更新最后登录日期
|
||
securityUserEntity.LastLoginDatetime = DateTime.Now;
|
||
psd = rsa.DecodeOrNull(data.UserPassword);
|
||
if (string.IsNullOrEmpty(psd)) throw new ValidatedException("认证不通过.");
|
||
securityUserEntity.UserPassword = psd.Substring(36, psd.Length - 36);
|
||
repository.UpdateNow(securityUserEntity);
|
||
|
||
IRepository<SecurityUserWebLoginEntity> repositoryLog = service.GetRepository<IRepository<SecurityUserWebLoginEntity>>();
|
||
|
||
SecurityUserWebLoginEntity webLogin = new SecurityUserWebLoginEntity
|
||
{
|
||
Username = securityUserEntity.UserName,
|
||
SessionId = clainmName,
|
||
LoginTime = DateTime.Now,
|
||
HostIp = httpContextAccessor.HttpContext.Connection.RemoteIpAddress?.MapToIPv4()?.ToString(),
|
||
HostUserAgent = this.httpContextAccessor?.HttpContext?.Request.Headers.UserAgent.ToString(),
|
||
RefreshToken = jwtGenerate.GenerateRefreshToken(),
|
||
RefreshTokenRefreshedTime = DateTime.Now,
|
||
};
|
||
|
||
repositoryLog.InsertNow(webLogin);
|
||
PermissionContext permissionContext = new PermissionContext(service);
|
||
return new LoginProfile
|
||
{
|
||
Token = new JwtInfo() { AccessToken = accessToken, RefreshToken = webLogin.RefreshToken, CreatedTime = webLogin.RefreshTokenRefreshedTime },
|
||
Username = securityUserEntity.UserName,
|
||
UserType = securityUserEntity.UserType,
|
||
UserLocalName = securityUserEntity.UserLocalName,
|
||
UserEngName = securityUserEntity.UserEngName,
|
||
UserMobile = securityUserEntity.UserMobile!,
|
||
PermissionInfo = permissionContext.GetUserPermissionInfo()
|
||
};
|
||
}
|
||
|
||
|
||
[AllowAnonymous]
|
||
[HttpGet]
|
||
public string GetRsaPublicKey()
|
||
{
|
||
if (string.IsNullOrEmpty(service.Configuration["SecuritySettings:RsaPublicKey"]))
|
||
throw new ValidatedException("[SecuritySettings:RsaPublicKey]");
|
||
return service.Configuration["SecuritySettings:RsaPublicKey"]!;
|
||
}
|
||
|
||
[AllowAnonymous]
|
||
public JwtInfo RefreshToken(JwtInfo jwtInfo)
|
||
{
|
||
if (jwtInfo == null || string.IsNullOrEmpty(jwtInfo.AccessToken) || string.IsNullOrEmpty(jwtInfo.RefreshToken))
|
||
throw new ServiceErrorException("无效的令牌,请重新登录.");
|
||
|
||
TokenValidationParameters parameters = new TokenValidationParameters
|
||
{
|
||
ValidateIssuerSigningKey = true,
|
||
//获取或设置要使用的Microsoft.IdentityModel.Tokens.SecurityKey用于签名验证。
|
||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(service.CloudBuilder.CloudBuilderOptions.Jwt.Secret)),
|
||
//获取或设置一个System.String,它表示将使用的有效发行者检查代币的发行者。
|
||
ValidIssuer = service.CloudBuilder.CloudBuilderOptions.Jwt.Issuer,
|
||
//获取或设置一个字符串,该字符串表示将用于检查的有效受众反对令牌的观众。
|
||
ValidAudience = service.CloudBuilder.CloudBuilderOptions.Jwt.Audience,
|
||
ValidateIssuer = true,
|
||
ValidateAudience = true,
|
||
ValidateLifetime = false,//不验证过期时间
|
||
};
|
||
|
||
// 验证 Token
|
||
var tokenHandler = new JwtSecurityTokenHandler();
|
||
SecurityToken vTocken;
|
||
string token = jwtInfo.AccessToken.Replace("Bearer ", "");
|
||
try
|
||
{
|
||
var tokenValidationResult = tokenHandler.ValidateToken(token, parameters, out vTocken);
|
||
|
||
if (tokenValidationResult == null || !tokenValidationResult.Identities.Any() || !tokenValidationResult.Identities.First().IsAuthenticated)
|
||
throw new ServiceErrorException("无效的令牌,请重新登录.");
|
||
}
|
||
catch (Exception)
|
||
{
|
||
throw new ServiceErrorException("无效的令牌,请重新登录.");
|
||
}
|
||
|
||
string clainmName = ClaimPolicy.GetClaimValue(token, ClaimPolicy.CLAINM_NAME);
|
||
string username = ClaimPolicy.GetClaimValue(token, ClaimPolicy.CLAINM_USERID);
|
||
string userMobile = ClaimPolicy.GetClaimValue(token, ClaimPolicy.CLAINM_ACCOUNT);
|
||
string locale = ClaimPolicy.GetClaimValue(token, ClaimPolicy.CLAINM_LOCALE);
|
||
if (string.IsNullOrEmpty(clainmName) || string.IsNullOrEmpty(username))
|
||
throw new ServiceErrorException("无效的令牌,请重新登录.");
|
||
|
||
IRepository<SecurityUserEntity> repositorySecurityUser = service.GetRepository<IRepository<SecurityUserEntity>>();
|
||
|
||
SecurityUserEntity user = repositorySecurityUser.DetachedEntities.Where(x => x.UserName == username && x.UserIsValidIndc == YesNoPolicy.YES).FirstOrDefault();
|
||
if (user == null) throw new ServiceErrorException("无效的令牌,请重新登录.");
|
||
|
||
IRepository<SecurityUserWebLoginEntity> repositoryLog = service.GetRepository<IRepository<SecurityUserWebLoginEntity>>();
|
||
|
||
SecurityUserWebLoginEntity log = repositoryLog.DetachedEntities.Where(x => x.Username == username && x.SessionId == clainmName).FirstOrDefault()!;
|
||
|
||
//不是最后登录的令牌失效
|
||
DateTime? LoginTime = repositoryLog.DetachedEntities.Where(x => x.Username == username).Max(x => x.LoginTime);
|
||
if (LoginTime.HasValue && log.LoginTime < LoginTime.Value) throw new ServiceErrorException("无效的令牌,请重新登录.");
|
||
|
||
if (log == null || log.RefreshToken != jwtInfo.RefreshToken || log.LogoutTime.HasValue ||
|
||
log.RefreshToken != jwtInfo.RefreshToken || log.RefreshTokenRefreshedTime.AddMinutes(Convert.ToInt32(service.CloudBuilder.CloudBuilderOptions.Jwt.RefreshExpireMins)) < DateTime.Now)
|
||
throw new ServiceErrorException("无效的令牌,请重新登录.");
|
||
|
||
JwtGenerate jwtGenerate = service.ServiceProvider.GetService<JwtGenerate>()!;
|
||
|
||
Dictionary<string, string> claims = new Dictionary<string, string>();
|
||
claims.Add(ClaimPolicy.CLAINM_NAME, clainmName);
|
||
claims.Add(ClaimPolicy.CLAINM_ACCOUNT, userMobile);
|
||
claims.Add(ClaimPolicy.CLAINM_USERID, username);
|
||
claims.Add(ClaimPolicy.CLAINM_LOCALE, locale??CulturePolicy.ZH_CN);
|
||
|
||
var accessToken = jwtGenerate.Generate(claims);
|
||
|
||
log.RefreshToken = jwtGenerate.GenerateRefreshToken();
|
||
log.RefreshTokenRefreshedTime = DateTime.Now;
|
||
|
||
if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey("Authorization"))
|
||
httpContextAccessor.HttpContext.Request.Headers.Remove("Authorization");
|
||
httpContextAccessor.HttpContext.Request.Headers.Add("Authorization", "Bearer " + accessToken);
|
||
|
||
repositoryLog.UpdateNow(log);
|
||
|
||
jwtInfo.AccessToken = accessToken;
|
||
jwtInfo.RefreshToken = log.RefreshToken;
|
||
jwtInfo.CreatedTime = log.RefreshTokenRefreshedTime;
|
||
|
||
return jwtInfo;
|
||
}
|
||
|
||
[AllowAnonymous]
|
||
public void Logout()
|
||
{
|
||
string username = ClaimPolicy.GetClaimValue(httpContextAccessor, ClaimPolicy.CLAINM_USERID);
|
||
string clainmName = ClaimPolicy.GetClaimValue(httpContextAccessor, ClaimPolicy.CLAINM_NAME);
|
||
|
||
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(clainmName)) { return; }
|
||
|
||
|
||
IRepository<SecurityUserWebLoginEntity> repositoryLog = service.GetRepository<IRepository<SecurityUserWebLoginEntity>>();
|
||
|
||
SecurityUserWebLoginEntity log = repositoryLog.DetachedEntities.Where(x => x.Username == username && x.SessionId == clainmName).FirstOrDefault()!;
|
||
if (log == null || log.LogoutTime.HasValue) { return; }
|
||
|
||
log.LogoutTime = DateTime.Now;
|
||
|
||
repositoryLog.UpdateNow(log);
|
||
}
|
||
|
||
}
|
||
}
|