using System;
using System.Linq;
using System.Threading.Tasks;
using ZhonTai.Admin.Core.Configs;
using ZhonTai.Common.Helpers;
using ZhonTai.Admin.Core.Dto;
using ZhonTai.Admin.Domain.Permission;
using ZhonTai.Admin.Domain.User;
using ZhonTai.Admin.Domain.Tenant;
using ZhonTai.Admin.Services.Auth.Dto;
using ZhonTai.Admin.Domain.RolePermission;
using ZhonTai.Admin.Domain.UserRole;
using ZhonTai.Admin.Services.Contracts;
using ZhonTai.Admin.Tools.Captcha;
using ZhonTai.DynamicApi;
using ZhonTai.DynamicApi.Attributes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using StackExchange.Profiling;
using Microsoft.AspNetCore.Mvc;
using ZhonTai.Admin.Core.Attributes;
using ZhonTai.Admin.Services.LoginLog.Dto;
using System.Diagnostics;
using ZhonTai.Admin.Services.LoginLog;
using ZhonTai.Admin.Core.Auth;
using System.Security.Claims;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using ZhonTai.Common.Extensions;
using ZhonTai.Admin.Services.User;
using ZhonTai.Admin.Core.Consts;
namespace ZhonTai.Admin.Services.Auth
{
///
/// 认证授权服务
///
[DynamicApi(Area = "admin")]
public class AuthService : BaseService, IAuthService, IDynamicApi
{
private readonly AppConfig _appConfig;
private readonly IPermissionRepository _permissionRepository;
private readonly IUserRepository _userRepository;
private readonly ITenantRepository _tenantRepository;
private readonly ICaptchaTool _captchaTool;
public AuthService(
AppConfig appConfig,
IUserRepository userRepository,
IPermissionRepository permissionRepository,
ITenantRepository tenantRepository,
ICaptchaTool captchaTool
)
{
_appConfig = appConfig;
_userRepository = userRepository;
_permissionRepository = permissionRepository;
_tenantRepository = tenantRepository;
_captchaTool = captchaTool;
}
///
/// 获得token
///
/// 用户信息
///
private string GetToken(AuthLoginOutput user)
{
if (user == null)
{
return string.Empty;
}
var token = LazyGetRequiredService().Create(new[]
{
new Claim(ClaimAttributes.UserId, user.Id.ToString()),
new Claim(ClaimAttributes.UserName, user.UserName),
new Claim(ClaimAttributes.UserNickName, user.NickName),
new Claim(ClaimAttributes.TenantId, user.TenantId.ToString()),
new Claim(ClaimAttributes.TenantType, user.TenantType.ToString()),
new Claim(ClaimAttributes.DataIsolationType, user.DataIsolationType.ToString())
});
return token;
}
///
/// 查询密钥
///
///
[HttpGet]
[AllowAnonymous]
[NoOprationLog]
public async Task GetPasswordEncryptKeyAsync()
{
//写入Redis
var guid = Guid.NewGuid().ToString("N");
var key = string.Format(CacheKey.PassWordEncryptKey, guid);
var encyptKey = StringHelper.GenerateRandom(8);
await Cache.SetAsync(key, encyptKey, TimeSpan.FromMinutes(5));
var data = new { key = guid, encyptKey };
return ResultOutput.Ok(data);
}
///
/// 查询用户信息
///
///
[Login]
public async Task GetUserInfoAsync()
{
if (!(User?.Id > 0))
{
return ResultOutput.NotOk("未登录!");
}
var authUserInfoOutput = new AuthUserInfoOutput
{
//用户信息
User = await _userRepository.GetAsync(User.Id),
//用户菜单
Menus = await _permissionRepository.Select
.Where(a => new[] { PermissionTypeEnum.Group, PermissionTypeEnum.Menu }.Contains(a.Type))
.Where(a =>
_permissionRepository.Orm.Select()
.InnerJoin((b, c) => b.RoleId == c.RoleId && c.UserId == User.Id)
.Where(b => b.PermissionId == a.Id)
.Any()
)
.OrderBy(a => a.ParentId)
.OrderBy(a => a.Sort)
.ToListAsync(a => new AuthUserMenuDto { ViewPath = a.View.Path }),
//用户权限点
Permissions = await _permissionRepository.Select
.Where(a => a.Type == PermissionTypeEnum.Dot)
.Where(a =>
_permissionRepository.Orm.Select()
.InnerJoin((b, c) => b.RoleId == c.RoleId && c.UserId == User.Id)
.Where(b => b.PermissionId == a.Id)
.Any()
)
.ToListAsync(a => a.Code)
};
return ResultOutput.Ok(authUserInfoOutput);
}
///
/// 登录
///
///
///
[HttpPost]
[AllowAnonymous]
[NoOprationLog]
public async Task LoginAsync(AuthLoginInput input)
{
var sw = new Stopwatch();
sw.Start();
#region 验证码校验
if (_appConfig.VarifyCode.Enable)
{
input.Captcha.DeleteCache = true;
input.Captcha.CaptchaKey = CacheKey.CaptchaKey;
var isOk = await _captchaTool.CheckAsync(input.Captcha);
if (!isOk)
{
return ResultOutput.NotOk("安全验证不通过,请重新登录!");
}
}
#endregion 验证码校验
UserEntity user = null;
user = await _userRepository.Select.DisableGlobalFilter("Tenant").Where(a => a.UserName == input.UserName).ToOneAsync();
if (!(user?.Id > 0))
{
return ResultOutput.NotOk("账号输入有误!", 3);
}
#region 解密
if (input.PasswordKey.NotNull())
{
var passwordEncryptKey = string.Format(CacheKey.PassWordEncryptKey, input.PasswordKey);
var existsPasswordKey = await Cache.ExistsAsync(passwordEncryptKey);
if (existsPasswordKey)
{
var secretKey = await Cache.GetAsync(passwordEncryptKey);
if (secretKey.IsNull())
{
return ResultOutput.NotOk("解密失败!", 1);
}
input.Password = DesEncrypt.Decrypt(input.Password, secretKey);
await Cache.DelAsync(passwordEncryptKey);
}
else
{
return ResultOutput.NotOk("解密失败!", 1);
}
}
#endregion 解密
var password = MD5Encrypt.Encrypt32(input.Password);
if (user.Password != password)
{
return ResultOutput.NotOk("密码输入有误!", 4);
}
var authLoginOutput = Mapper.Map(user);
if (_appConfig.Tenant)
{
var tenant = await _tenantRepository.Select.DisableGlobalFilter("Tenant").WhereDynamic(user.TenantId).ToOneAsync(a => new { a.TenantType, a.DataIsolationType });
authLoginOutput.TenantType = tenant.TenantType;
authLoginOutput.DataIsolationType = tenant.DataIsolationType;
}
string token = GetToken(authLoginOutput);
sw.Stop();
#region 添加登录日志
var loginLogAddInput = new LoginLogAddInput
{
CreatedUserName = input.UserName,
ElapsedMilliseconds = sw.ElapsedMilliseconds,
Status = true,
CreatedUserId = authLoginOutput.Id,
NickName = authLoginOutput.NickName,
TenantId = authLoginOutput.TenantId
};
await LazyGetRequiredService().AddAsync(loginLogAddInput);
#endregion 添加登录日志
return ResultOutput.Ok(new { token });
}
///
/// 刷新Token
/// 以旧换新
///
///
///
[HttpGet]
[AllowAnonymous]
public async Task Refresh([BindRequired] string token)
{
var userClaims = LazyGetRequiredService().Decode(token);
if (userClaims == null || userClaims.Length == 0)
{
return ResultOutput.NotOk();
}
var refreshExpires = userClaims.FirstOrDefault(a => a.Type == ClaimAttributes.RefreshExpires)?.Value;
if (refreshExpires.IsNull())
{
return ResultOutput.NotOk();
}
if (refreshExpires.ToLong() <= DateTime.Now.ToTimestamp())
{
return ResultOutput.NotOk("登录信息已过期");
}
var userId = userClaims.FirstOrDefault(a => a.Type == ClaimAttributes.UserId)?.Value;
if (userId.IsNull())
{
return ResultOutput.NotOk("登录信息已失效");
}
var output = await LazyGetRequiredService().GetLoginUserAsync(userId.ToLong());
string newToken = GetToken(output?.Data);
return ResultOutput.Ok(new { token = newToken });
}
///
/// 获取验证数据
///
///
[HttpGet]
[AllowAnonymous]
[NoOprationLog]
[EnableCors(AdminConsts.AllowAnyPolicyName)]
public async Task GetCaptcha()
{
using (MiniProfiler.Current.Step("获取滑块验证"))
{
var data = await _captchaTool.GetAsync(CacheKey.CaptchaKey);
return ResultOutput.Ok(data);
}
}
///
/// 检查验证数据
///
///
[HttpGet]
[AllowAnonymous]
[NoOprationLog]
[EnableCors(AdminConsts.AllowAnyPolicyName)]
public async Task CheckCaptcha([FromQuery] CaptchaInput input)
{
input.CaptchaKey = CacheKey.CaptchaKey;
var result = await _captchaTool.CheckAsync(input);
return ResultOutput.Result(result);
}
}
}