source: Farmatiko/Controllers/LoginController.cs@ ad60966

Last change on this file since ad60966 was d23bf72, checked in by DimitarSlezenkovski <dslezenkovski@…>, 3 years ago

Add SystemService, Auth, fix a lil bugs :)

  • Property mode set to 100644
File size: 8.6 KB
Line 
1using System;
2using System.ComponentModel.DataAnnotations;
3using System.Security.Claims;
4using System.Text.Json.Serialization;
5using System.Threading.Tasks;
6using FarmatikoData.Models;
7using FarmatikoServices.Auth;
8using FarmatikoServices.FarmatikoServiceInterfaces;
9using FarmatikoServices.Infrastructure;
10using Microsoft.AspNetCore.Authentication;
11using Microsoft.AspNetCore.Authorization;
12using Microsoft.AspNetCore.Http;
13using Microsoft.AspNetCore.Mvc;
14using Microsoft.Extensions.Logging;
15using Microsoft.IdentityModel.Tokens;
16
17namespace Farmatiko.Controllers
18{
19 [ApiController]
20 public class LoginController : ControllerBase
21 {
22 private readonly ILogger<LoginController> _logger;
23 private readonly IAuthService _authService;
24 private readonly IJwtAuthManager _jwtAuthManager;
25 private readonly IPHService _pHService;
26
27 public LoginController(ILogger<LoginController> logger, IAuthService authService, IJwtAuthManager jwtAuthManager, IPHService pHService)
28 {
29 _logger = logger;
30 _authService = authService;
31 _jwtAuthManager = jwtAuthManager;
32 _pHService = pHService;
33 }
34
35 [AllowAnonymous]
36 [HttpPost("api/pharmacyhead/login")]
37 public ActionResult Login([FromBody] LoginRequest request)
38 {
39 if (!ModelState.IsValid)
40 {
41 return BadRequest();
42 }
43
44 if (!_authService.IsValidUserCredentials(request.UserName, request.Password))
45 {
46 return Unauthorized();
47 }
48
49 var role = _authService.GetUserRole(request.UserName);
50 var claims = new[]
51 {
52 new Claim(ClaimTypes.Name,request.UserName),
53 new Claim(ClaimTypes.Role, role)
54 };
55
56 var jwtResult = _jwtAuthManager.GenerateTokens(request.UserName, claims, DateTime.Now);
57 _logger.LogInformation($"User [{request.UserName}] logged in the system.");
58 return Ok(new LoginResult
59 {
60 UserName = request.UserName,
61 Role = role,
62 AccessToken = jwtResult.AccessToken,
63 RefreshToken = jwtResult.RefreshToken.TokenString,
64 Head = _pHService.GetPharmacyHead(request.UserName)
65 });
66 }
67
68 [HttpGet("api/pharmacyhead/user")]
69 [Authorize]
70 public ActionResult GetCurrentUser()
71 {
72 return Ok(new LoginResult
73 {
74 UserName = User.Identity.Name,
75 Role = User.FindFirst(ClaimTypes.Role)?.Value ?? string.Empty,
76 OriginalUserName = User.FindFirst("OriginalUserName")?.Value
77 });
78 }
79
80 [HttpPost("api/pharmacyhead/logout")]
81 [Authorize]
82 public ActionResult Logout()
83 {
84 // optionally "revoke" JWT token on the server side --> add the current token to a block-list
85 // https://github.com/auth0/node-jsonwebtoken/issues/375
86
87 var userName = User.Identity.Name;
88 _jwtAuthManager.RemoveRefreshTokenByUserName(userName);
89 _logger.LogInformation($"User [{userName}] logged out the system.");
90 return Ok();
91 }
92
93 [HttpPost("api/pharmacyhead/refresh-token")]
94 [Authorize]
95 public async Task<ActionResult> RefreshToken([FromBody] RefreshTokenRequest request)
96 {
97 try
98 {
99 var userName = User.Identity.Name;
100 _logger.LogInformation($"User [{userName}] is trying to refresh JWT token.");
101
102 if (string.IsNullOrWhiteSpace(request.RefreshToken))
103 {
104 return Unauthorized();
105 }
106
107 var accessToken = await HttpContext.GetTokenAsync("Bearer", "access_token");
108 var jwtResult = _jwtAuthManager.Refresh(request.RefreshToken, accessToken, DateTime.Now);
109 _logger.LogInformation($"User [{userName}] has refreshed JWT token.");
110 return Ok(new LoginResult
111 {
112 UserName = userName,
113 Role = User.FindFirst(ClaimTypes.Role)?.Value ?? string.Empty,
114 AccessToken = jwtResult.AccessToken,
115 RefreshToken = jwtResult.RefreshToken.TokenString
116 });
117 }
118 catch (SecurityTokenException e)
119 {
120 return Unauthorized(e.Message); // return 401 so that the client side can redirect the user to login page
121 }
122 }
123
124 [HttpPost("api/pharmacyhead/impersonation")]
125 [Authorize(Roles = UserRoles.Admin)]
126 public ActionResult Impersonate([FromBody] ImpersonationRequest request)
127 {
128 var userName = User.Identity.Name;
129 _logger.LogInformation($"User [{userName}] is trying to impersonate [{request.UserName}].");
130
131 var impersonatedRole = _authService.GetUserRole(request.UserName);
132 if (string.IsNullOrWhiteSpace(impersonatedRole))
133 {
134 _logger.LogInformation($"User [{userName}] failed to impersonate [{request.UserName}] due to the target user not found.");
135 return BadRequest($"The target user [{request.UserName}] is not found.");
136 }
137 if (impersonatedRole == UserRoles.Admin)
138 {
139 _logger.LogInformation($"User [{userName}] is not allowed to impersonate another Admin.");
140 return BadRequest("This action is not supported.");
141 }
142
143 var claims = new[]
144 {
145 new Claim(ClaimTypes.Name,request.UserName),
146 new Claim(ClaimTypes.Role, impersonatedRole),
147 new Claim("OriginalUserName", userName)
148 };
149
150 var jwtResult = _jwtAuthManager.GenerateTokens(request.UserName, claims, DateTime.Now);
151 _logger.LogInformation($"User [{request.UserName}] is impersonating [{request.UserName}] in the system.");
152 return Ok(new LoginResult
153 {
154 UserName = request.UserName,
155 Role = impersonatedRole,
156 OriginalUserName = userName,
157 AccessToken = jwtResult.AccessToken,
158 RefreshToken = jwtResult.RefreshToken.TokenString
159 });
160 }
161
162 [HttpPost("api/pharmacyhead/stop-impersonation")]
163 public ActionResult StopImpersonation()
164 {
165 var userName = User.Identity.Name;
166 var originalUserName = User.FindFirst("OriginalUserName")?.Value;
167 if (string.IsNullOrWhiteSpace(originalUserName))
168 {
169 return BadRequest("You are not impersonating anyone.");
170 }
171 _logger.LogInformation($"User [{originalUserName}] is trying to stop impersonate [{userName}].");
172
173 var role = _authService.GetUserRole(originalUserName);
174 var claims = new[]
175 {
176 new Claim(ClaimTypes.Name,originalUserName),
177 new Claim(ClaimTypes.Role, role)
178 };
179
180 var jwtResult = _jwtAuthManager.GenerateTokens(originalUserName, claims, DateTime.Now);
181 _logger.LogInformation($"User [{originalUserName}] has stopped impersonation.");
182 return Ok(new LoginResult
183 {
184 UserName = originalUserName,
185 Role = role,
186 OriginalUserName = null,
187 AccessToken = jwtResult.AccessToken,
188 RefreshToken = jwtResult.RefreshToken.TokenString
189 });
190 }
191 }
192
193 public class LoginRequest
194 {
195 [Required]
196 [JsonPropertyName("username")]
197 public string UserName { get; set; }
198
199 [Required]
200 [JsonPropertyName("password")]
201 public string Password { get; set; }
202 }
203
204 public class LoginResult
205 {
206 [JsonPropertyName("username")]
207 public string UserName { get; set; }
208
209 [JsonPropertyName("role")]
210 public string Role { get; set; }
211
212 [JsonPropertyName("originalUserName")]
213 public string OriginalUserName { get; set; }
214
215 [JsonPropertyName("accessToken")]
216 public string AccessToken { get; set; }
217
218 [JsonPropertyName("refreshToken")]
219 public string RefreshToken { get; set; }
220 [JsonPropertyName("head")]
221 public PharmacyHead Head { get; set; }
222 }
223
224 public class RefreshTokenRequest
225 {
226 [JsonPropertyName("refreshToken")]
227 public string RefreshToken { get; set; }
228 }
229
230 public class ImpersonationRequest
231 {
232 [JsonPropertyName("username")]
233 public string UserName { get; set; }
234 }
235}
236
Note: See TracBrowser for help on using the repository browser.