140 lines
5.4 KiB
C#
140 lines
5.4 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Tiku.Application.Auth;
|
||
using Tiku.Api.Contracts;
|
||
|
||
namespace Tiku.Api.Controllers;
|
||
|
||
[ApiController]
|
||
[Route("api/auth")]
|
||
[Produces("application/json")]
|
||
public sealed class AuthController(IAuthService authService) : ControllerBase
|
||
{
|
||
[AllowAnonymous]
|
||
[HttpPost("login/password")]
|
||
[EndpointSummary("手机号密码登录")]
|
||
[EndpointDescription("使用本地手机号和密码登录,签发 JWT access token 与数据库 refresh/session。")]
|
||
[ProducesResponseType<AuthenticatedUserDto>(StatusCodes.Status200OK)]
|
||
[ProducesResponseType<ProblemDetails>(StatusCodes.Status401Unauthorized)]
|
||
public async Task<ActionResult<AuthenticatedUserDto>> LoginWithPassword(
|
||
[FromBody] PasswordLoginDto request,
|
||
CancellationToken cancellationToken)
|
||
{
|
||
var result = await authService.LoginWithPasswordAsync(
|
||
new PasswordLoginRequest(
|
||
request.TenantId,
|
||
request.Phone,
|
||
request.Password,
|
||
GetIpAddress(),
|
||
Request.Headers.UserAgent.ToString()),
|
||
cancellationToken);
|
||
|
||
return Ok(AuthenticatedUserDto.FromApplication(result));
|
||
}
|
||
|
||
[AllowAnonymous]
|
||
[HttpPost("login/sms")]
|
||
[EndpointSummary("短信验证码登录")]
|
||
[EndpointDescription("校验已发送的登录用途短信验证码,成功后签发 JWT access token 与数据库 refresh/session。")]
|
||
[ProducesResponseType<AuthenticatedUserDto>(StatusCodes.Status200OK)]
|
||
[ProducesResponseType<ProblemDetails>(StatusCodes.Status401Unauthorized)]
|
||
public async Task<ActionResult<AuthenticatedUserDto>> LoginWithSms(
|
||
[FromBody] SmsLoginDto request,
|
||
CancellationToken cancellationToken)
|
||
{
|
||
var result = await authService.LoginWithSmsAsync(
|
||
new SmsLoginRequest(
|
||
request.TenantId,
|
||
request.Phone,
|
||
request.Code,
|
||
GetIpAddress(),
|
||
Request.Headers.UserAgent.ToString()),
|
||
cancellationToken);
|
||
|
||
return Ok(AuthenticatedUserDto.FromApplication(result));
|
||
}
|
||
|
||
[AllowAnonymous]
|
||
[HttpPost("oauth/wechat")]
|
||
[EndpointSummary("微信网页 OAuth 登录")]
|
||
[EndpointDescription("使用微信网页授权 code 换取 openid/unionid,upsert 用户身份并创建应用会话。")]
|
||
[ProducesResponseType<AuthenticatedUserDto>(StatusCodes.Status200OK)]
|
||
[ProducesResponseType<ProblemDetails>(StatusCodes.Status401Unauthorized)]
|
||
[ProducesResponseType<ProblemDetails>(StatusCodes.Status503ServiceUnavailable)]
|
||
public async Task<ActionResult<AuthenticatedUserDto>> LoginWithWechatWeb(
|
||
[FromBody] OAuthCodeDto request,
|
||
CancellationToken cancellationToken)
|
||
{
|
||
var result = await authService.LoginWithWechatWebAsync(
|
||
new WechatLoginRequest(
|
||
request.TenantId,
|
||
request.Code,
|
||
GetIpAddress(),
|
||
Request.Headers.UserAgent.ToString()),
|
||
cancellationToken);
|
||
|
||
return Ok(AuthenticatedUserDto.FromApplication(result));
|
||
}
|
||
|
||
[AllowAnonymous]
|
||
[HttpPost("oauth/wechat-miniapp")]
|
||
[EndpointSummary("微信小程序登录")]
|
||
[EndpointDescription("使用小程序 wx.login 返回的 code 换取 openid/session_key,upsert 用户身份并创建应用会话。")]
|
||
[ProducesResponseType<AuthenticatedUserDto>(StatusCodes.Status200OK)]
|
||
[ProducesResponseType<ProblemDetails>(StatusCodes.Status401Unauthorized)]
|
||
[ProducesResponseType<ProblemDetails>(StatusCodes.Status503ServiceUnavailable)]
|
||
public async Task<ActionResult<AuthenticatedUserDto>> LoginWithWechatMiniApp(
|
||
[FromBody] OAuthCodeDto request,
|
||
CancellationToken cancellationToken)
|
||
{
|
||
var result = await authService.LoginWithWechatMiniAppAsync(
|
||
new WechatLoginRequest(
|
||
request.TenantId,
|
||
request.Code,
|
||
GetIpAddress(),
|
||
Request.Headers.UserAgent.ToString()),
|
||
cancellationToken);
|
||
|
||
return Ok(AuthenticatedUserDto.FromApplication(result));
|
||
}
|
||
|
||
[AllowAnonymous]
|
||
[HttpPost("refresh")]
|
||
[EndpointSummary("刷新登录会话")]
|
||
[EndpointDescription("使用 refresh token 轮换数据库 session,并签发新的 access/refresh token。")]
|
||
public async Task<ActionResult<AuthTokenPair>> Refresh(
|
||
[FromBody] RefreshSessionDto request,
|
||
CancellationToken cancellationToken)
|
||
{
|
||
var result = await authService.RefreshAsync(
|
||
new RefreshSessionRequest(
|
||
request.RefreshToken,
|
||
GetIpAddress(),
|
||
Request.Headers.UserAgent.ToString()),
|
||
cancellationToken);
|
||
|
||
return Ok(result);
|
||
}
|
||
|
||
[AllowAnonymous]
|
||
[HttpPost("logout")]
|
||
[EndpointSummary("退出登录")]
|
||
[EndpointDescription("撤销 refresh token 对应的数据库 session;session 校验开启时,旧 access token 也会被拒绝。")]
|
||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||
public async Task<IActionResult> Logout(
|
||
[FromBody] RefreshSessionDto request,
|
||
CancellationToken cancellationToken)
|
||
{
|
||
await authService.LogoutAsync(
|
||
new LogoutSessionRequest(request.RefreshToken),
|
||
cancellationToken);
|
||
|
||
return NoContent();
|
||
}
|
||
|
||
private string? GetIpAddress()
|
||
{
|
||
return HttpContext.Connection.RemoteIpAddress?.ToString();
|
||
}
|
||
}
|