profileShare

rasmusjy / splitapp-backend-clean-onion

Read-only snapshot

No repository description.

main default branch 429 files Expires Sep 13, 2026, 9:06 AM
AccountController.cs 4,608 bytes
1 using System.Net;
2 using System.Security.Claims;
3 using App.BLL.Services.Identity;
4 using App.DTO.v1;
5 using App.DTO.v1.Identity;
6 using Asp.Versioning;
7 using Microsoft.AspNetCore.Authentication.JwtBearer;
8 using Microsoft.AspNetCore.Authorization;
9 using Microsoft.AspNetCore.Mvc;
10
11 namespace WebApp.ApiControllers.Identity;
12
13 [ApiVersion("1.0")]
14 [ApiController]
15 [Route("/api/v{version:apiVersion}/identity/[controller]/[action]")]
16 public class AccountController : ControllerBase
17 {
18 private readonly IIdentityService _identityService;
19 private readonly ILogger<AccountController> _logger;
20
21 public AccountController(IIdentityService identityService, ILogger<AccountController> logger)
22 {
23 _identityService = identityService;
24 _logger = logger;
25 }
26
27 [HttpPost]
28 [Produces("application/json")]
29 [Consumes("application/json")]
30 [ProducesResponseType<JWTResponse>((int)HttpStatusCode.OK)]
31 [ProducesResponseType<RestApiErrorResponse>((int)HttpStatusCode.BadRequest)]
32 public async Task<ActionResult<JWTResponse>> Register(
33 [FromBody] RegisterInfo registrationData,
34 [FromQuery] int expiresInSeconds)
35 {
36 var result = await _identityService.RegisterAsync(new RegisterRequest
37 {
38 Email = registrationData.Email,
39 Password = registrationData.Password,
40 FirstName = registrationData.Firstname,
41 LastName = registrationData.Lastname,
42 ExpiresInSeconds = expiresInSeconds
43 });
44
45 if (!result.Success)
46 {
47 _logger.LogWarning("WebApi register failed for {Email}: {Error}", registrationData.Email, result.Error);
48 return MapErrorResult(result);
49 }
50
51 return Ok(MapJwtPayload(result.Payload!));
52 }
53
54 [HttpPost]
55 public async Task<ActionResult<JWTResponse>> Login(
56 [FromBody] LoginInfo loginInfo,
57 [FromQuery] int expiresInSeconds)
58 {
59 var result = await _identityService.LoginAsync(new LoginRequest
60 {
61 Email = loginInfo.Email,
62 Password = loginInfo.Password,
63 ExpiresInSeconds = expiresInSeconds
64 });
65
66 if (!result.Success)
67 {
68 _logger.LogWarning("WebApi login failed for {Email}: {Error}", loginInfo.Email, result.Error);
69 return MapErrorResult(result);
70 }
71
72 return Ok(MapJwtPayload(result.Payload!));
73 }
74
75 [HttpPost]
76 public async Task<ActionResult<JWTResponse>> RefreshTokenData(
77 [FromBody] TokenRefreshInfo tokenRefreshInfo,
78 [FromQuery] int expiresInSeconds)
79 {
80 var result = await _identityService.RefreshTokenAsync(new RefreshRequest
81 {
82 Jwt = tokenRefreshInfo.Jwt,
83 RefreshToken = tokenRefreshInfo.RefreshToken,
84 ExpiresInSeconds = expiresInSeconds
85 });
86
87 if (!result.Success)
88 {
89 return MapErrorResult(result);
90 }
91
92 return Ok(MapJwtPayload(result.Payload!));
93 }
94
95 [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
96 [HttpPost]
97 public async Task<ActionResult> Logout([FromBody] LogoutInfo logout)
98 {
99 var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier);
100 if (userIdStr == null || !Guid.TryParse(userIdStr, out var userId))
101 {
102 return BadRequest(new RestApiErrorResponse
103 {
104 Status = HttpStatusCode.BadRequest,
105 Error = "Invalid refresh token"
106 });
107 }
108
109 var result = await _identityService.LogoutAsync(new LogoutRequest
110 {
111 UserId = userId,
112 RefreshToken = logout.RefreshToken
113 });
114
115 if (!result.Success)
116 {
117 return MapErrorResult(result);
118 }
119
120 return Ok(new { TokenDeleteCount = result.TokensDeleted ?? 0 });
121 }
122
123 private ActionResult MapErrorResult(IdentityServiceResult result)
124 {
125 var error = new RestApiErrorResponse
126 {
127 Status = result.ErrorKind == IdentityServiceErrorKind.NotFound
128 ? HttpStatusCode.NotFound
129 : HttpStatusCode.BadRequest,
130 Error = result.Error ?? "Unknown error"
131 };
132
133 return result.ErrorKind == IdentityServiceErrorKind.NotFound
134 ? NotFound(error)
135 : BadRequest(error);
136 }
137
138 private static JWTResponse MapJwtPayload(IdentityJwtPayload payload) => new()
139 {
140 Jwt = payload.Jwt,
141 RefreshToken = payload.RefreshToken,
142 FirstName = payload.FirstName,
143 LastName = payload.LastName
144 };
145 }
146