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#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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);
}
}
}