2025-03-22 12:16:22 +00:00
|
|
|
|
using GraphQL;
|
|
|
|
|
|
using LY.App.Common.Cypher;
|
|
|
|
|
|
using LY.App.Common.Redis;
|
2025-03-29 14:50:23 +00:00
|
|
|
|
using LY.App.Extensions.DI;
|
2025-03-22 12:16:22 +00:00
|
|
|
|
using LY.App.Model;
|
|
|
|
|
|
using Mapster;
|
|
|
|
|
|
using Microsoft.IdentityModel.Tokens;
|
|
|
|
|
|
using SqlSugar;
|
|
|
|
|
|
using StackExchange.Redis;
|
|
|
|
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
|
|
|
|
using System.Security.Claims;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
|
|
namespace LY.App.Service
|
|
|
|
|
|
{
|
2025-03-29 14:50:23 +00:00
|
|
|
|
[ServiceInjection(InjectionType.Transient)]
|
2025-03-22 12:16:22 +00:00
|
|
|
|
public class UserService
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly SqlSugarClient _db;
|
|
|
|
|
|
private readonly IConfiguration _config;
|
|
|
|
|
|
private readonly RedisService _redisService;
|
|
|
|
|
|
public UserService(SqlSugarClient db, IConfiguration config, RedisService redisService)
|
|
|
|
|
|
{
|
|
|
|
|
|
_db = db;
|
|
|
|
|
|
_config = config;
|
|
|
|
|
|
_redisService = redisService;
|
|
|
|
|
|
}
|
|
|
|
|
|
#region 增删改查
|
|
|
|
|
|
|
2025-03-24 02:59:34 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
///
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="input"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-03-22 12:16:22 +00:00
|
|
|
|
public async Task<ApiResult> Add(AddUser input)
|
|
|
|
|
|
{
|
|
|
|
|
|
var exists = await _db.Queryable<UserEntity>().AnyAsync(s => s.Name == input.Name && s.Disable == false);
|
|
|
|
|
|
if (!exists)
|
|
|
|
|
|
{
|
|
|
|
|
|
var entity = input.Adapt<UserEntity>();
|
|
|
|
|
|
// var entity = _mapper.Map<UserEntity>(input);
|
|
|
|
|
|
entity.CreateTime = DateTime.Now;
|
|
|
|
|
|
entity.UpdatePwdTime = DateTime.Now;
|
|
|
|
|
|
entity.Password = MD5CypherUtil.Hash("ly_" + input.Password);
|
|
|
|
|
|
var Id = await _db.Insertable(entity).ExecuteReturnSnowflakeIdAsync();
|
|
|
|
|
|
return new ApiResult() { code = 0, data = Id.ToString() };
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return new ApiResult() { code = 1, msg = "已存在该用户名" };
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 删除用户,标记删除,不是物理删除
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="ids"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public async Task<string> SoftDelete(IEnumerable<long> ids)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ids.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var item in ids)
|
|
|
|
|
|
{
|
|
|
|
|
|
var entity = await _db.Queryable<UserEntity>().FirstAsync(s => s.Id == item);
|
|
|
|
|
|
if (entity?.Name != "admin")
|
|
|
|
|
|
{
|
|
|
|
|
|
entity.Disable = entity.Disable == true ? false : true;
|
|
|
|
|
|
await _db.Updateable<UserEntity>(entity).ExecuteCommandAsync();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
return "admin 不可删除!";
|
|
|
|
|
|
}
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
|
|
|
|
|
return "ids不能为空";
|
|
|
|
|
|
}
|
2025-03-24 02:59:34 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取用户信息
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="userId"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-03-22 12:16:22 +00:00
|
|
|
|
public async Task<ApiResult> GetUserById(long userId)
|
|
|
|
|
|
{
|
|
|
|
|
|
var entity = await _db.Queryable<UserEntity>().FirstAsync(s => s.Id == userId);
|
|
|
|
|
|
if (entity != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
entity.Password = "";
|
|
|
|
|
|
return new ApiResult() { code = 0, data = entity };
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 监测登录次数
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="username"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private async Task<bool> CheckLoginNum(string username)
|
|
|
|
|
|
{
|
|
|
|
|
|
int num = 0;
|
|
|
|
|
|
// var node = SettingHelper.Instance.GetNode("Vertify", "LoginFailed");
|
|
|
|
|
|
var node = _config["Vertify"];
|
|
|
|
|
|
var key = RedisKeyList.LogNum(username);
|
|
|
|
|
|
var val = await _redisService.GetAsync<int>(key);
|
|
|
|
|
|
if (num >= int.Parse(node))
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2025-03-24 02:59:34 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 登录
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="input"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-03-22 12:16:22 +00:00
|
|
|
|
public async Task<ApiResult> Login(LoginModel input)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (await CheckLoginNum(input.username))
|
|
|
|
|
|
{
|
|
|
|
|
|
return new ApiResult()
|
|
|
|
|
|
{
|
|
|
|
|
|
code = 1,
|
|
|
|
|
|
msg = "连续登录失败5次,锁定30分钟"
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
var password = MD5CypherUtil.Hash("ly_" + input.password);
|
|
|
|
|
|
var entity = await _db.Queryable<UserEntity>()
|
|
|
|
|
|
.Where(s => s.Disable == false &&
|
|
|
|
|
|
s.Name == input.username && s.Password == password).FirstAsync();
|
|
|
|
|
|
if (entity == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
await SetLoginNum(input.username);
|
|
|
|
|
|
return new ApiResult()
|
|
|
|
|
|
{
|
|
|
|
|
|
code = 1,
|
|
|
|
|
|
msg = "请检查用户名跟密码!"
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
entity.LoginTime = DateTime.Now;
|
|
|
|
|
|
await _db.Updateable(entity).ExecuteCommandAsync();
|
|
|
|
|
|
await RemoveLoginNum(input.username);
|
|
|
|
|
|
string token = CreateToken(entity);
|
|
|
|
|
|
//加入redis
|
|
|
|
|
|
await _redisService.SetAsync<string>(RedisKeyList.TokenUser(input.username),
|
|
|
|
|
|
token, TimeSpan.FromSeconds(60 * 60 * 24 * 7));
|
2025-06-14 05:17:14 +00:00
|
|
|
|
var positionIds = entity.positionId?.Select(s => s.ToString()).ToList();
|
2025-03-22 12:16:22 +00:00
|
|
|
|
return new ApiResult()
|
|
|
|
|
|
{
|
|
|
|
|
|
code = 1,
|
|
|
|
|
|
data = new
|
|
|
|
|
|
{
|
|
|
|
|
|
token,
|
2025-06-14 05:17:14 +00:00
|
|
|
|
expires = DateTime.UtcNow.AddSeconds(60 * 60 * 24 * 7),
|
2025-03-22 12:16:22 +00:00
|
|
|
|
isAdmin = entity.IsAdmin,
|
2025-06-14 05:17:14 +00:00
|
|
|
|
userid = entity.Id.ToString(),
|
|
|
|
|
|
positionIds
|
2025-03-22 12:16:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
private async Task RemoveLoginNum(string username)
|
|
|
|
|
|
{
|
|
|
|
|
|
var key = $"login_num_{username}";
|
|
|
|
|
|
await _redisService.DeleteAsync(key);
|
|
|
|
|
|
}
|
|
|
|
|
|
private async Task SetLoginNum(string username)
|
|
|
|
|
|
{
|
|
|
|
|
|
var key = RedisKeyList.LogNum(username);
|
|
|
|
|
|
var num = await _redisService.GetAsync<int>(key);
|
|
|
|
|
|
await _redisService.SetAsync(key, num + 1, TimeSpan.FromMinutes(30));
|
|
|
|
|
|
}
|
|
|
|
|
|
private string CreateToken(UserEntity user)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建JWT的密钥
|
|
|
|
|
|
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Token:SecretKey"]));
|
|
|
|
|
|
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建Claims
|
|
|
|
|
|
var claims = new[]
|
|
|
|
|
|
{
|
|
|
|
|
|
new Claim(JwtRegisteredClaimNames.Sub,user.Name),
|
|
|
|
|
|
new Claim(JwtRegisteredClaimNames.Sid, user.Id.ToString())
|
|
|
|
|
|
// 还可以添加其他需要的Claims
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 创建Token
|
|
|
|
|
|
var token = new JwtSecurityToken(
|
|
|
|
|
|
issuer: _config["Token:Issuer"],
|
|
|
|
|
|
audience: _config["Token:Audience"],
|
|
|
|
|
|
claims: claims,
|
|
|
|
|
|
expires: DateTime.UtcNow.AddSeconds(60 * 60 * 24 * 7), // 设置Token过期时间
|
|
|
|
|
|
signingCredentials: credentials
|
|
|
|
|
|
);
|
|
|
|
|
|
// 生成Token字符串
|
|
|
|
|
|
var tokenString = new JwtSecurityTokenHandler().WriteToken(token);
|
|
|
|
|
|
return tokenString;
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
///
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="pageSize"></param>
|
|
|
|
|
|
/// <param name="pageNum"></param>
|
|
|
|
|
|
/// <param name="key"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public async Task<object> GetPage(int pageSize, int pageNum, string key)
|
|
|
|
|
|
{
|
|
|
|
|
|
RefAsync<int> total = 0;
|
|
|
|
|
|
var query = await _db.Queryable<UserEntity>()
|
2025-03-24 02:59:34 +00:00
|
|
|
|
.Where(s => s.Disable == false)
|
|
|
|
|
|
.WhereIF(!string.IsNullOrEmpty(key), s => s.Name.Contains(key))
|
|
|
|
|
|
.OrderBy(s => s.Id)
|
|
|
|
|
|
.ToPageListAsync(pageNum, pageSize, total);
|
2025-06-15 10:40:58 +00:00
|
|
|
|
query.ForEach(s =>
|
|
|
|
|
|
{
|
2025-06-22 10:11:25 +00:00
|
|
|
|
if (s.positionId is not null && s.positionId.Any())
|
2025-06-15 10:40:58 +00:00
|
|
|
|
{
|
2025-06-22 10:11:25 +00:00
|
|
|
|
s.positionName = _db.Queryable<PositionInfo>().Where(p => s.positionId.Contains(p.Id.ToString())).Select(p => p.Name).ToList();
|
2025-06-15 10:40:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-03-22 12:16:22 +00:00
|
|
|
|
return new
|
|
|
|
|
|
{
|
|
|
|
|
|
total = total.Value,
|
|
|
|
|
|
items = query
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新密码
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="input"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public async Task<string> UpdatePwd(UpdatePwdDto input)
|
|
|
|
|
|
{
|
|
|
|
|
|
var md5 = MD5CypherUtil.Hash("ly_" + input.oldPwd);
|
|
|
|
|
|
var entity = await _db.Queryable<UserEntity>().FirstAsync(s => s.Id == input.Id);
|
|
|
|
|
|
if (entity.Password == md5)
|
|
|
|
|
|
{
|
|
|
|
|
|
entity.Password = MD5CypherUtil.Hash("ly_" + input.newPwd);
|
|
|
|
|
|
entity.UpdatePwdTime = DateTime.Now;
|
|
|
|
|
|
await _db.Updateable(entity).UpdateColumns(s => new
|
|
|
|
|
|
{
|
|
|
|
|
|
s.Password,
|
|
|
|
|
|
s.UpdatePwdTime
|
|
|
|
|
|
}).ExecuteCommandAsync();
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
|
|
|
|
|
return "原密码不正确";
|
|
|
|
|
|
}
|
|
|
|
|
|
public async Task<string> Update(UpdateUser input)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!string.IsNullOrEmpty(input.Name))
|
|
|
|
|
|
{
|
|
|
|
|
|
var entity = input.Adapt<UserEntity>();
|
|
|
|
|
|
await _db.Updateable(entity).UpdateColumns(it => new
|
|
|
|
|
|
{
|
2025-06-25 16:40:06 +00:00
|
|
|
|
it.IsAdmin,
|
|
|
|
|
|
it.positionId
|
2025-03-22 12:16:22 +00:00
|
|
|
|
}).ExecuteCommandAsync();
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
return "用户名不能为空";
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|