学院管理员限制在所属学院。 辅导员通过稳定账号 ID 绑定行政班,避免重名串班。 教师只能访问本人档案、授课课程和所授课学生。 学生只能访问本人档案及所在班级课程。 教师/学生角色会自动校验并绑定工号或学号档案。 超级管理员可在用户页面调整角色、学院、工号/学号,并预览生效后的数据范围。
95 lines
3.0 KiB
C#
95 lines
3.0 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
using System.Security.Claims;
|
|
using Jiaowu.Api.Domain.Identity;
|
|
using Jiaowu.Api.Infrastructure.Auth;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
namespace Jiaowu.Api.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/auth")]
|
|
public sealed class AuthController(
|
|
UserManager<ApplicationUser> userManager,
|
|
ITokenService tokenService) : ControllerBase
|
|
{
|
|
[AllowAnonymous]
|
|
[HttpPost("login")]
|
|
public async Task<ActionResult<LoginResponse>> Login(LoginRequest request)
|
|
{
|
|
var user = await userManager.FindByNameAsync(request.UserName);
|
|
if (user is null || !user.IsEnabled)
|
|
{
|
|
return Unauthorized(new ProblemDetails
|
|
{
|
|
Title = "登录失败",
|
|
Detail = "账号或密码不正确,或账号已停用。",
|
|
Status = StatusCodes.Status401Unauthorized
|
|
});
|
|
}
|
|
|
|
if (await userManager.IsLockedOutAsync(user) ||
|
|
!await userManager.CheckPasswordAsync(user, request.Password))
|
|
{
|
|
await userManager.AccessFailedAsync(user);
|
|
return Unauthorized(new ProblemDetails
|
|
{
|
|
Title = "登录失败",
|
|
Detail = "账号或密码不正确,或账号已停用。",
|
|
Status = StatusCodes.Status401Unauthorized
|
|
});
|
|
}
|
|
|
|
await userManager.ResetAccessFailedCountAsync(user);
|
|
user.LastLoginAt = DateTime.UtcNow;
|
|
await userManager.UpdateAsync(user);
|
|
var roles = await userManager.GetRolesAsync(user);
|
|
|
|
return new LoginResponse(
|
|
tokenService.Create(user, roles),
|
|
new CurrentUserResponse(
|
|
user.Id,
|
|
user.UserName!,
|
|
user.DisplayName,
|
|
roles,
|
|
user.CollegeId,
|
|
EffectiveDataScopeResolver.Resolve(roles).ToString()));
|
|
}
|
|
|
|
[Authorize]
|
|
[HttpGet("me")]
|
|
public async Task<ActionResult<CurrentUserResponse>> Me()
|
|
{
|
|
var id = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
|
var user = id is null ? null : await userManager.FindByIdAsync(id);
|
|
if (user is null || !user.IsEnabled)
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
var roles = await userManager.GetRolesAsync(user);
|
|
return new CurrentUserResponse(
|
|
user.Id,
|
|
user.UserName!,
|
|
user.DisplayName,
|
|
roles,
|
|
user.CollegeId,
|
|
EffectiveDataScopeResolver.Resolve(roles).ToString());
|
|
}
|
|
}
|
|
|
|
public sealed record LoginRequest(
|
|
[Required, MaxLength(100)] string UserName,
|
|
[Required, MaxLength(100)] string Password);
|
|
|
|
public sealed record LoginResponse(string Token, CurrentUserResponse User);
|
|
|
|
public sealed record CurrentUserResponse(
|
|
Guid Id,
|
|
string UserName,
|
|
string DisplayName,
|
|
IEnumerable<string> Roles,
|
|
Guid? CollegeId,
|
|
string EffectiveDataScope);
|