You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
13 KiB
C#

1 year ago
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Admin.Core.Common;
using Admin.Core.Extensions;
using Admin.Core.IService;
using Admin.Core.IService.ISys;
using Admin.Core.Model;
using Admin.Core.Model.Sys;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using UAParser;
namespace Admin.Core.Api
{
/// <summary>
/// 登录管理
/// </summary>
[Produces("application/json")]
[Route("api/Login")]
[Authorize(Permissions.Name)]
public class LoginController : BaseApiUserController
{
readonly ISysMenuService _sysMenuService;
readonly ISysPermissionService _sysPermissionService;
readonly ISysLoginInfoService _sysLoginInfoService;
readonly ICaptcha _captcha;
readonly ISysConfigService _sysConfigService;
readonly PermissionRequirement _requirement;
/// <summary>
/// 构造函数注入
/// </summary>
/// <param name="sysUserService"></param>
/// <param name="sysMenuService"></param>
/// <param name="sysPermissionService"></param>
/// <param name="captcha"></param>
/// <param name="requirement"></param>
/// <param name="sysLoginInfoService"></param>
/// <param name="sysConfigService"></param>
public LoginController(ISysUserService sysUserService, ISysMenuService sysMenuService, ISysPermissionService sysPermissionService,
ICaptcha captcha, PermissionRequirement requirement, ISysLoginInfoService sysLoginInfoService,
ISysConfigService sysConfigService) : base(sysUserService)
{
_sysUserService = sysUserService;
_sysMenuService = sysMenuService;
_sysPermissionService = sysPermissionService;
_sysLoginInfoService = sysLoginInfoService;
_captcha = captcha;
_sysConfigService = sysConfigService;
_requirement = requirement;
}
/// <summary>
/// 登录获取Token-JWT
/// </summary>
/// <param name="loginBody"></param>
/// <returns></returns>
[HttpPost]
[Route("Login")]
[AllowAnonymous]
public async Task<MessageModel<TokenInfoViewModel>> GetJwtToken([FromBody] LoginBody loginBody)
{
string jwtStr = string.Empty;
if (!loginBody.IsNotEmptyOrNull() || string.IsNullOrEmpty(loginBody.LoginName) || string.IsNullOrEmpty(loginBody.Password))
{
return Failed<TokenInfoViewModel>("用户名或密码不能为空");
}
// 验证码校验
var captchaOnOff = (await _sysConfigService.QueryAsync(x => x.ConfigKey == SysConst.KEY_OFF_CAPTCHA)).FirstOrDefault();
if (captchaOnOff.ConfigValue == "true")
{
if (!loginBody.Code.IsNotEmptyOrNull())
{
return Failed<TokenInfoViewModel>("验证码错误");
}
var code = CookieHelper.GetCookies(HttpContext, CacheKey.Captcha);
if (loginBody.Code.ToLower() != code.ToLower())
{
return Failed<TokenInfoViewModel>("验证码错误");
}
}
loginBody.Password = MD5Helper.MD5Encrypt32(loginBody.Password);
var user = (await _sysUserService.QueryAsync(d => d.LoginName == loginBody.LoginName && d.Password == loginBody.Password && d.DelFlag == false && d.Status == SysConst.ENABLE)).FirstOrDefault();
if (user.IsNotEmptyOrNull())
{
var userRoles = await _sysUserService.GetUserRoleNameStr(loginBody.LoginName, loginBody.Password);
//如果是基于用户的授权策略,这里要添加用户;如果是基于角色的授权策略,这里要添加角色
var claims = new List<Claim> {
new Claim(ClaimTypes.Name, user.LoginName.ToString()),
new Claim(ClaimTypes.Sid, user.UserID.ToString()),
new Claim(JwtRegisteredClaimNames.Jti, user.UserID.ToString()),
new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) };
claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
var token = JwtToken.BuildJwtToken(claims.ToArray(), _requirement);
//记录登录信息
await RecordLoginInfo(user);
return Success(token, "获取成功");
}
else
{
user = (await _sysUserService.QueryAsync(d => d.LoginName == loginBody.LoginName && d.DelFlag == false)).FirstOrDefault();
if (user == null)
{
return Failed<TokenInfoViewModel>("用户不存在");
}
user = (await _sysUserService.QueryAsync(d => d.LoginName == loginBody.LoginName && d.DelFlag == false && d.Status == SysConst.DISABLE)).FirstOrDefault();
if (user != null)
{
return Failed<TokenInfoViewModel>("用户处于禁用状态");
}
return Failed<TokenInfoViewModel>("用户名或密码错误");
}
}
/// <summary>
/// 默认使用管理员账号登录获取Token-JWT
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("LoginAdmin")]
[AllowAnonymous]
public async Task<MessageModel<TokenInfoViewModel>> GetJwtTokenAdmin()
{
// 是否开启测试环境
var isTestCurrent = Appsettings.app(new string[] { "AppSettings", "UseLoadTest" }).ObjToBool();
if (!isTestCurrent) return Failed<TokenInfoViewModel>("测试环境未开启");
string jwtStr = string.Empty;
//管理员账号信息
string loginName = "admin";
string password = "Password01!";
password = MD5Helper.MD5Encrypt32(password);
var user = (await _sysUserService.QueryAsync(d => d.LoginName == loginName && d.Password == password && d.DelFlag == false && d.Status == SysConst.ENABLE)).FirstOrDefault();
if (user.IsNotEmptyOrNull())
{
var userRoles = await _sysUserService.GetUserRoleNameStr(loginName, password);
//如果是基于用户的授权策略,这里要添加用户;如果是基于角色的授权策略,这里要添加角色
var claims = new List<Claim> {
new Claim(ClaimTypes.Name, user.LoginName.ToString()),
new Claim(ClaimTypes.Sid, user.UserID.ToString()),
new Claim(JwtRegisteredClaimNames.Jti, user.UserID.ToString()),
new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) };
claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
var token = JwtToken.BuildJwtToken(claims.ToArray(), _requirement);
return Success(token, "获取成功");
}
else
{
return Failed<TokenInfoViewModel>("认证失败");
}
}
/// <summary>
/// 请求刷新Token以旧换新
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet]
[Route("RefreshToken")]
[AllowAnonymous]
public async Task<MessageModel<TokenInfoViewModel>> RefreshToken(string token = "")
{
string jwtStr = string.Empty;
if (string.IsNullOrEmpty(token))
return Failed<TokenInfoViewModel>("token无效请重新登录");
var tokenModel = JwtHelper.SerializeJwt(token);
if (tokenModel != null && tokenModel.Uid > 0)
{
var user = await _sysUserService.QueryByIdAsync(tokenModel.Uid);
if (user != null)
{
var userRoles = await _sysUserService.GetUserRoleNameStr(user.LoginName, user.Password);
//如果是基于用户的授权策略,这里要添加用户;如果是基于角色的授权策略,这里要添加角色
var claims = new List<Claim> {
new Claim(ClaimTypes.Name, tokenModel.Uid.ObjToString()),
new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ObjToString()),
new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) };
claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
//用户标识
var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
identity.AddClaims(claims);
var refreshToken = JwtToken.BuildJwtToken(claims.ToArray(), _requirement);
return Success(refreshToken, "获取成功");
}
}
return Failed<TokenInfoViewModel>("认证失败!");
}
/// <summary>
/// 获取用户信息
/// </summary>
/// <returns> 用户信息 </returns>
[HttpGet]
[Route("GetUserInfo")]
public async Task<MessageModel<UserPermission>> GetUserInfo()
{
UserPermission userPermission = new UserPermission()
{
SysUser = await _sysUserService.QueryByIdAsync(CurrentUser.UserID),
Perms = await _sysPermissionService.GetMenuPermission(CurrentUser.UserID),
Roles = await _sysPermissionService.GetRolePermission(CurrentUser.UserID)
};
return Success(userPermission);
}
/// <summary>
/// 获取路由信息
/// </summary>
/// <returns> 路由信息 </returns>
[HttpGet]
[Route("GetRouters")]
public async Task<MessageModel<List<RouterVo>>> GetRouters()
{
var menus = await _sysMenuService.SelectMenuTreeByUserId(CurrentUser.UserID);
return Success(_sysMenuService.BuildMenus(menus));
}
/// <summary>
/// 生成验证码
/// </summary>
/// <param name="_captcha"></param>
/// <returns></returns>
[HttpGet]
[Route("Captcha")]
[AllowAnonymous]
public async Task<FileContentResult> Captcha()
{
var code = await _captcha.GenerateRandomCaptcha();
var result = await _captcha.GenerateCaptchaImage(code);
// 将验证码的token放入cookie
CookieHelper.SetCookies(HttpContext, CacheKey.Captcha, code);
return File(result.CaptchaMemoryStream.ToArray(), "image/png");
}
/// <summary>
/// 退出登录
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
[HttpPost]
[Route("Logout")]
[AllowAnonymous]
public MessageModel<bool> Logout(string token = "")
{
var refresh = RefreshToken(token).Result;
return Success(refresh.data.IsNotEmptyOrNull() && refresh.data.token.IsNotEmptyOrNull());
}
/// <summary>
/// 用户注册
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
[HttpPost]
[Route("Register")]
[AllowAnonymous]
public async Task<MessageModel<bool>> Register([FromBody] SysUser user)
{
MessageModel<bool> model = new MessageModel<bool>();
if (await _sysUserService.CheckLoginNameUnique(user.LoginName))
{
model.success = false;
model.msg = "登录账号已存在!";
return model;
}
user.Password = MD5Helper.MD5Encrypt32(user.Password);
user.UserType = "00";
user.DelFlag = false;
user.CreateTime = DateTime.Now;
user.UpdateTime = DateTime.Now;
user.CreateBy = user.LoginName;
user.UpdateBy = user.LoginName;
user.Status = SysConst.ENABLE;
user.Sex = 0;
return Success(await _sysUserService.AddAsync(user) > 0);
}
/// <summary>
/// 记录登录信息
/// </summary>
/// <param name="user"></param>
[NonAction]
public async Task RecordLoginInfo(SysUser user)
{
user.LoginIP = IpHelper.GetIpAddr(HttpContext);
user.LoginDate = DateTime.Now;
await _sysUserService.UpdateAsync(user);
var agent = HttpContext.Request.Headers["User-Agent"].ObjToString();
var parser = Parser.GetDefault();
var info = parser.Parse(agent);
SysLoginInfo loginInfo = new SysLoginInfo()
{
UserName = user.LoginName,
IPAddr = user.LoginIP,
LoginLocation = AddressHelper.GetRealAddressByIP(user.LoginIP),
Browser = info.UA.Family,
OS = info.OS.Family,
Status = SysConst.SUCCESS,
Msg = user.UserName,
LoginTime = DateTime.Now
};
await _sysLoginInfoService.AddAsync(loginInfo);
}
}
}