Merge pull request 'feature-nxdev' (#19) from feature-nxdev into main
Reviewed-on: #19
This commit is contained in:
commit
7c0cf6941f
14
backend/IM_API/Configs/MapperConfig.cs
Normal file
14
backend/IM_API/Configs/MapperConfig.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using AutoMapper;
|
||||
using IM_API.Dtos;
|
||||
using IM_API.Models;
|
||||
|
||||
namespace IM_API.Configs
|
||||
{
|
||||
public class MapperConfig:Profile
|
||||
{
|
||||
public MapperConfig()
|
||||
{
|
||||
CreateMap<User, UserInfoDto>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,16 @@
|
||||
namespace IM_API.Configs
|
||||
using IM_API.Interface.Services;
|
||||
using IM_API.Services;
|
||||
|
||||
namespace IM_API.Configs
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddAllService(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddAutoMapper(typeof(MapperConfig));
|
||||
services.AddTransient<IAuthService, AuthService>();
|
||||
services.AddSingleton<IJWTService, JWTService>();
|
||||
services.AddSingleton<IRefreshTokenService,RedisRefreshTokenService>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
37
backend/IM_API/Controllers/AuthController.cs
Normal file
37
backend/IM_API/Controllers/AuthController.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using IM_API.Dtos;
|
||||
using IM_API.Interface.Services;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IM_API.Controllers
|
||||
{
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class AuthController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<AuthController> _logger;
|
||||
private readonly IAuthService _authService;
|
||||
private readonly IJWTService _jwtService;
|
||||
private readonly IRefreshTokenService _refreshTokenService;
|
||||
private readonly IConfiguration _configuration;
|
||||
public AuthController(ILogger<AuthController> logger, IAuthService authService, IJWTService jwtService, IRefreshTokenService refreshTokenService, IConfiguration configuration)
|
||||
{
|
||||
_logger = logger;
|
||||
_authService = authService;
|
||||
_jwtService = jwtService;
|
||||
_refreshTokenService = refreshTokenService;
|
||||
_configuration = configuration;
|
||||
}
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Login(LoginRequestDto dto)
|
||||
{
|
||||
var user = await _authService.LoginAsync(dto);
|
||||
//生成凭证
|
||||
(string token,DateTime expiresAt) = _jwtService.CreateAccessTokenForUser(user.Id,user.Username,"user");
|
||||
//生成刷新凭证
|
||||
string refreshToken = await _refreshTokenService.CreateRefreshTokenAsync(user.Id);
|
||||
var res = new BaseResponse<LoginDto>(new LoginDto(user.Id,token,refreshToken,expiresAt));
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IM_API.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class WeatherForecastController : ControllerBase
|
||||
{
|
||||
private static readonly string[] Summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
private readonly ILogger<WeatherForecastController> _logger;
|
||||
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet(Name = "GetWeatherForecast")]
|
||||
public IEnumerable<WeatherForecast> Get()
|
||||
{
|
||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
|
||||
TemperatureC = Random.Shared.Next(-20, 55),
|
||||
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,6 @@
|
||||
namespace IM_API.Dtos
|
||||
using IM_API.Tools;
|
||||
|
||||
namespace IM_API.Dtos
|
||||
{
|
||||
public class BaseResponse<T>
|
||||
{
|
||||
@ -20,13 +22,23 @@
|
||||
this.Data = data;
|
||||
}
|
||||
/// <summary>
|
||||
/// 默认成功响应返回仅数据
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public BaseResponse(T data)
|
||||
{
|
||||
this.Code = CodeDefine.SUCCESS.Code;
|
||||
this.Message = CodeDefine.SUCCESS.Message;
|
||||
this.Data = data;
|
||||
}
|
||||
/// <summary>
|
||||
/// 默认成功响应返回,不带数据
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="data"></param>
|
||||
public BaseResponse(string msg)
|
||||
{
|
||||
this.Code = 0;
|
||||
this.Code = CodeDefine.SUCCESS.Code;
|
||||
this.Message = msg;
|
||||
}
|
||||
/// <summary>
|
||||
|
||||
@ -5,5 +5,12 @@
|
||||
public int Id { get; set; }
|
||||
public string Token { get; set; }
|
||||
public string RefreshToken { get; set; }
|
||||
public DateTime ExpireAt { get; set; }
|
||||
public LoginDto(int id,string token,string refreshToken,DateTime expireAt) {
|
||||
this.Id = id;
|
||||
this.Token = token;
|
||||
this.RefreshToken = refreshToken;
|
||||
this.ExpireAt = expireAt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,5 +4,6 @@
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string NickName { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
17
backend/IM_API/Exceptions/BaseException.cs
Normal file
17
backend/IM_API/Exceptions/BaseException.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using IM_API.Tools;
|
||||
|
||||
namespace IM_API.Exceptions
|
||||
{
|
||||
public class BaseException:Exception
|
||||
{
|
||||
public int Code { get; set; }
|
||||
|
||||
public BaseException(int code,string message) : base(message) {
|
||||
this.Code = code;
|
||||
}
|
||||
public BaseException(CodeDefine codeDefine) : base(codeDefine.Message)
|
||||
{
|
||||
this.Code = codeDefine.Code;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="12.0.1" />
|
||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.21" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.21">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ActiveDebugProfile>http</ActiveDebugProfile>
|
||||
<Controller_SelectedScaffolderID>ApiControllerEmptyScaffolder</Controller_SelectedScaffolderID>
|
||||
<Controller_SelectedScaffolderCategoryPath>root/Common/Api</Controller_SelectedScaffolderCategoryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
|
||||
|
||||
@ -10,30 +10,12 @@ namespace IM_API.Interface.Services
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
Task<LoginDto> LoginAsync(LoginRequestDto dto);
|
||||
Task<User> LoginAsync(LoginRequestDto dto);
|
||||
/// <summary>
|
||||
/// 注册
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
Task<UserInfoDto> RegisterAsync(RegisterRequestDto dto);
|
||||
/// <summary>
|
||||
/// 生成登录凭证
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
string GenerateToken(User user);
|
||||
/// <summary>
|
||||
/// 验证登录凭证
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
int? ValidateToken(string token);
|
||||
/// <summary>
|
||||
/// 刷新令牌
|
||||
/// </summary>
|
||||
/// <param name="refreshToken"></param>
|
||||
/// <returns></returns>
|
||||
LoginDto RefreshToken(string refreshToken);
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,6 +62,7 @@ public partial class ImContext : DbContext
|
||||
|
||||
modelBuilder.Entity<Admin>(entity =>
|
||||
{
|
||||
entity.Ignore(x => x.StateEnum);
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
@ -101,6 +102,7 @@ public partial class ImContext : DbContext
|
||||
|
||||
modelBuilder.Entity<Conversation>(entity =>
|
||||
{
|
||||
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
@ -145,6 +147,7 @@ public partial class ImContext : DbContext
|
||||
|
||||
modelBuilder.Entity<Device>(entity =>
|
||||
{
|
||||
entity.Ignore(x => x.DtypeEnum);
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
@ -216,6 +219,7 @@ public partial class ImContext : DbContext
|
||||
|
||||
modelBuilder.Entity<Friend>(entity =>
|
||||
{
|
||||
entity.Ignore(x => x.StatusEnum);
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
@ -258,6 +262,7 @@ public partial class ImContext : DbContext
|
||||
|
||||
modelBuilder.Entity<FriendRequest>(entity =>
|
||||
{
|
||||
entity.Ignore(x => x.StateEnum);
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
@ -301,6 +306,9 @@ public partial class ImContext : DbContext
|
||||
|
||||
modelBuilder.Entity<Group>(entity =>
|
||||
{
|
||||
entity.Ignore(x => x.StatusEnum);
|
||||
entity.Ignore(x => x.AllMembersBannedEnum);
|
||||
entity.Ignore(x => x.AuhorityEnum);
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
@ -345,6 +353,7 @@ public partial class ImContext : DbContext
|
||||
|
||||
modelBuilder.Entity<GroupInvite>(entity =>
|
||||
{
|
||||
entity.Ignore(x => x.StateEnum);
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
@ -393,6 +402,7 @@ public partial class ImContext : DbContext
|
||||
|
||||
modelBuilder.Entity<GroupMember>(entity =>
|
||||
{
|
||||
entity.Ignore(x => x.RoleEnum);
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
@ -436,6 +446,7 @@ public partial class ImContext : DbContext
|
||||
|
||||
modelBuilder.Entity<GroupRequest>(entity =>
|
||||
{
|
||||
entity.Ignore(x => x.StateEnum);
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
@ -477,6 +488,7 @@ public partial class ImContext : DbContext
|
||||
|
||||
modelBuilder.Entity<LoginLog>(entity =>
|
||||
{
|
||||
entity.Ignore(x => x.StateEnum);
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
@ -511,6 +523,8 @@ public partial class ImContext : DbContext
|
||||
|
||||
modelBuilder.Entity<Message>(entity =>
|
||||
{
|
||||
entity.Ignore(x => x.StateEnum);
|
||||
entity.Ignore(x => x.MsgTypeEnum);
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
@ -675,6 +689,10 @@ public partial class ImContext : DbContext
|
||||
|
||||
modelBuilder.Entity<User>(entity =>
|
||||
{
|
||||
|
||||
// 忽略包装枚举属性
|
||||
entity.Ignore(e => e.OnlineStatusEnum);
|
||||
entity.Ignore(e => e.StatusEnum);
|
||||
entity.HasKey(e => e.Id).HasName("PRIMARY");
|
||||
|
||||
entity
|
||||
|
||||
57
backend/IM_API/Services/AuthService.cs
Normal file
57
backend/IM_API/Services/AuthService.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using AutoMapper;
|
||||
using IM_API.Dtos;
|
||||
using IM_API.Exceptions;
|
||||
using IM_API.Interface.Services;
|
||||
using IM_API.Models;
|
||||
using IM_API.Tools;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace IM_API.Services
|
||||
{
|
||||
public class AuthService : IAuthService
|
||||
{
|
||||
private readonly ImContext _context;
|
||||
private readonly ILogger<AuthService> _logger;
|
||||
private readonly IMapper _mapper;
|
||||
public AuthService(ImContext context, ILogger<AuthService> logger, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<User> LoginAsync(LoginRequestDto dto)
|
||||
{
|
||||
string username = dto.Username;
|
||||
string password = dto.Password;
|
||||
var user = await _context.Users.FirstOrDefaultAsync(x => x.Username == username && x.Password == password);
|
||||
if(user is null)
|
||||
{
|
||||
throw new BaseException(CodeDefine.PASSWORD_ERROR);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
public async Task<UserInfoDto> RegisterAsync(RegisterRequestDto dto)
|
||||
{
|
||||
string username = dto.Username;
|
||||
string password = dto.Password;
|
||||
string nickname = dto.NickName;
|
||||
//用户是否存在
|
||||
bool isExist = await _context.Users.AnyAsync(x => x.Username == username);
|
||||
if (isExist) throw new BaseException(CodeDefine.USER_ALREADY_EXISTS);
|
||||
User user = new User
|
||||
{
|
||||
Username = username,
|
||||
Password = password,
|
||||
NickName = nickname,
|
||||
OnlineStatusEnum = UserOnlineStatus.Offline,
|
||||
StatusEnum = UserStatus.Normal,
|
||||
Created = DateTime.Now
|
||||
};
|
||||
_context.Users.Add(user);
|
||||
await _context.SaveChangesAsync();
|
||||
return _mapper.Map<UserInfoDto>(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
102
backend/IM_API/Tools/CodeDefine.cs
Normal file
102
backend/IM_API/Tools/CodeDefine.cs
Normal file
@ -0,0 +1,102 @@
|
||||
namespace IM_API.Tools
|
||||
{
|
||||
public class CodeDefine
|
||||
{
|
||||
public int Code { get; set; }
|
||||
public string Message { get; set; }
|
||||
|
||||
public CodeDefine(int code, string message)
|
||||
{
|
||||
Code = code;
|
||||
Message = message;
|
||||
}
|
||||
// 3.1 成功类
|
||||
/// <summary>成功响应</summary>
|
||||
public static CodeDefine SUCCESS = new CodeDefine(0, "成功");
|
||||
|
||||
// 3.2 系统级错误(1000 ~ 1999)
|
||||
/// <summary>未知异常</summary>
|
||||
public static CodeDefine SYSTEM_ERROR = new CodeDefine(1000, "系统错误");
|
||||
/// <summary>服务器维护中或宕机</summary>
|
||||
public static CodeDefine SERVICE_UNAVAILABLE = new CodeDefine(1001, "服务不可用");
|
||||
/// <summary>后端超时</summary>
|
||||
public static CodeDefine REQUEST_TIMEOUT = new CodeDefine(1002, "请求超时");
|
||||
/// <summary>缺少或参数不合法</summary>
|
||||
public static CodeDefine PARAMETER_ERROR = new CodeDefine(1003, "参数错误");
|
||||
/// <summary>数据库读写失败</summary>
|
||||
public static CodeDefine DATABASE_ERROR = new CodeDefine(1004, "数据库错误");
|
||||
/// <summary>无权限访问</summary>
|
||||
public static CodeDefine PERMISSION_DENIED = new CodeDefine(1005, "权限不足");
|
||||
/// <summary>Token 无效/过期</summary>
|
||||
public static CodeDefine AUTH_FAILED = new CodeDefine(1006, "认证失败");
|
||||
|
||||
// 3.3 用户相关错误(2000 ~ 2099)
|
||||
/// <summary>查询不到用户</summary>
|
||||
public static CodeDefine USER_NOT_FOUND = new CodeDefine(2000, "用户不存在");
|
||||
/// <summary>注册时用户已存在</summary>
|
||||
public static CodeDefine USER_ALREADY_EXISTS = new CodeDefine(2001, "用户已存在");
|
||||
/// <summary>登录密码错误</summary>
|
||||
public static CodeDefine PASSWORD_ERROR = new CodeDefine(2002, "密码错误");
|
||||
/// <summary>被管理员封禁</summary>
|
||||
public static CodeDefine USER_DISABLED = new CodeDefine(2003, "用户被禁用");
|
||||
/// <summary>需重新登录</summary>
|
||||
public static CodeDefine LOGIN_EXPIRED = new CodeDefine(2004, "登录过期");
|
||||
|
||||
// 3.4 好友相关错误(2100 ~ 2199)
|
||||
/// <summary>重复申请</summary>
|
||||
public static CodeDefine FRIEND_REQUEST_EXISTS = new CodeDefine(2100, "好友申请已存在");
|
||||
/// <summary>不是好友</summary>
|
||||
public static CodeDefine FRIEND_RELATION_NOT_FOUND = new CodeDefine(2101, "好友关系不存在");
|
||||
/// <summary>重复添加</summary>
|
||||
public static CodeDefine ALREADY_FRIENDS = new CodeDefine(2102, "已经是好友");
|
||||
/// <summary>被对方拒绝</summary>
|
||||
public static CodeDefine FRIEND_REQUEST_REJECTED = new CodeDefine(2103, "好友请求被拒绝");
|
||||
/// <summary>被对方拉黑</summary>
|
||||
public static CodeDefine CANNOT_ADD_FRIEND = new CodeDefine(2104, "无法申请加好友");
|
||||
|
||||
// 3.5 群聊相关错误(2200 ~ 2299)
|
||||
/// <summary>查询不到群</summary>
|
||||
public static CodeDefine GROUP_NOT_FOUND = new CodeDefine(2200, "群不存在");
|
||||
/// <summary>不能重复加入</summary>
|
||||
public static CodeDefine ALREADY_IN_GROUP = new CodeDefine(2201, "已在群中");
|
||||
/// <summary>超出限制</summary>
|
||||
public static CodeDefine GROUP_FULL = new CodeDefine(2202, "群成员已满");
|
||||
/// <summary>需要邀请/验证</summary>
|
||||
public static CodeDefine NO_GROUP_PERMISSION = new CodeDefine(2203, "无加群权限");
|
||||
/// <summary>邀请链接过期</summary>
|
||||
public static CodeDefine GROUP_INVITE_EXPIRED = new CodeDefine(2204, "群邀请已过期");
|
||||
|
||||
// 3.6 消息相关错误(2300 ~ 2399)
|
||||
/// <summary>发送时异常</summary>
|
||||
public static CodeDefine MESSAGE_SEND_FAILED = new CodeDefine(2300, "消息发送失败");
|
||||
/// <summary>查询不到消息</summary>
|
||||
public static CodeDefine MESSAGE_NOT_FOUND = new CodeDefine(2301, "消息不存在");
|
||||
/// <summary>超过时间限制</summary>
|
||||
public static CodeDefine MESSAGE_RECALL_FAILED = new CodeDefine(2302, "消息撤回失败");
|
||||
/// <summary>message_type 不合法</summary>
|
||||
public static CodeDefine UNSUPPORTED_MESSAGE_TYPE = new CodeDefine(2303, "不支持的消息类型");
|
||||
|
||||
// 3.7 文件相关错误(2400 ~ 2499)
|
||||
/// <summary>存储服务错误</summary>
|
||||
public static CodeDefine FILE_UPLOAD_FAILED = new CodeDefine(2400, "文件上传失败");
|
||||
/// <summary>下载时未找到</summary>
|
||||
public static CodeDefine FILE_NOT_FOUND = new CodeDefine(2401, "文件不存在");
|
||||
/// <summary>超过配置限制</summary>
|
||||
public static CodeDefine FILE_TOO_LARGE = new CodeDefine(2402, "文件大小超限");
|
||||
/// <summary>格式不允许</summary>
|
||||
public static CodeDefine FILE_TYPE_NOT_SUPPORTED = new CodeDefine(2403, "文件类型不支持");
|
||||
|
||||
// 3.8 管理后台相关错误(3000 ~ 3099)
|
||||
/// <summary>账号错误</summary>
|
||||
public static CodeDefine ADMIN_NOT_FOUND = new CodeDefine(3000, "管理员不存在");
|
||||
/// <summary>后台登录失败</summary>
|
||||
public static CodeDefine ADMIN_PASSWORD_ERROR = new CodeDefine(3001, "密码错误");
|
||||
/// <summary>角色未找到</summary>
|
||||
public static CodeDefine ROLE_NOT_FOUND = new CodeDefine(3002, "角色不存在");
|
||||
/// <summary>无操作权限</summary>
|
||||
public static CodeDefine ADMIN_PERMISSION_DENIED = new CodeDefine(3003, "权限不足");
|
||||
/// <summary>后台日志写入失败</summary>
|
||||
public static CodeDefine OPERATION_LOG_FAILED = new CodeDefine(3004, "操作记录失败");
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user