source: Farmatiko/Controllers/LoginController.cs@ 8e74e2f

Last change on this file since 8e74e2f was 1db5673, checked in by DimitarSlezenkovski <dslezenkovski@…>, 3 years ago

Fix bugs, add some more

  • Property mode set to 100644
File size: 9.0 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
114 Role = User.FindFirst(ClaimTypes.Role)?.Value ?? string.Empty,
115 AccessToken = jwtResult.AccessToken,
116 RefreshToken = jwtResult.RefreshToken.TokenString*/
117
118 UserName = userName,
119 Role = User.FindFirst(ClaimTypes.Role)?.Value ?? string.Empty,
120 AccessToken = jwtResult.AccessToken,
121 RefreshToken = jwtResult.RefreshToken.TokenString,
122 Head = _pHService.GetPharmacyHead(userName)
123 });
124 }
125 catch (SecurityTokenException e)
126 {
127 return Unauthorized(e.Message); // return 401 so that the client side can redirect the user to login page
128 }
129 }
130
131 [HttpPost("api/pharmacyhead/impersonation")]
132 [Authorize(Roles = UserRoles.Admin)]
133 public ActionResult Impersonate([FromBody] ImpersonationRequest request)
134 {
135 var userName = User.Identity.Name;
136 _logger.LogInformation($"User [{userName}] is trying to impersonate [{request.UserName}].");
137
138 var impersonatedRole = _authService.GetUserRole(request.UserName);
139 if (string.IsNullOrWhiteSpace(impersonatedRole))
140 {
141 _logger.LogInformation($"User [{userName}] failed to impersonate [{request.UserName}] due to the target user not found.");
142 return BadRequest($"The target user [{request.UserName}] is not found.");
143 }
144 if (impersonatedRole == UserRoles.Admin)
145 {
146 _logger.LogInformation($"User [{userName}] is not allowed to impersonate another Admin.");
147 return BadRequest("This action is not supported.");
148 }
149
150 var claims = new[]
151 {
152 new Claim(ClaimTypes.Name,request.UserName),
153 new Claim(ClaimTypes.Role, impersonatedRole),
154 new Claim("OriginalUserName", userName)
155 };
156
157 var jwtResult = _jwtAuthManager.GenerateTokens(request.UserName, claims, DateTime.Now);
158 _logger.LogInformation($"User [{request.UserName}] is impersonating [{request.UserName}] in the system.");
159 return Ok(new LoginResult
160 {
161 UserName = request.UserName,
162 Role = impersonatedRole,
163 OriginalUserName = userName,
164 AccessToken = jwtResult.AccessToken,
165 RefreshToken = jwtResult.RefreshToken.TokenString,
166 Head = _pHService.GetPharmacyHead(userName)
167 });
168 }
169
170 [HttpPost("api/pharmacyhead/stop-impersonation")]
171 public ActionResult StopImpersonation()
172 {
173 var userName = User.Identity.Name;
174 var originalUserName = User.FindFirst("OriginalUserName")?.Value;
175 if (string.IsNullOrWhiteSpace(originalUserName))
176 {
177 return BadRequest("You are not impersonating anyone.");
178 }
179 _logger.LogInformation($"User [{originalUserName}] is trying to stop impersonate [{userName}].");
180
181 var role = _authService.GetUserRole(originalUserName);
182 var claims = new[]
183 {
184 new Claim(ClaimTypes.Name,originalUserName),
185 new Claim(ClaimTypes.Role, role)
186 };
187
188 var jwtResult = _jwtAuthManager.GenerateTokens(originalUserName, claims, DateTime.Now);
189 _logger.LogInformation($"User [{originalUserName}] has stopped impersonation.");
190 return Ok(new LoginResult
191 {
192 UserName = originalUserName,
193 Role = role,
194 OriginalUserName = null,
195 AccessToken = jwtResult.AccessToken,
196 RefreshToken = jwtResult.RefreshToken.TokenString,
197 Head = _pHService.GetPharmacyHead(userName)
198 });
199 }
200 }
201
202 public class LoginRequest
203 {
204 [Required]
205 [JsonPropertyName("username")]
206 public string UserName { get; set; }
207
208 [Required]
209 [JsonPropertyName("password")]
210 public string Password { get; set; }
211 }
212
213 public class LoginResult
214 {
215 [JsonPropertyName("userName")]
216 public string UserName { get; set; }
217
218 [JsonPropertyName("role")]
219 public string Role { get; set; }
220
221 [JsonPropertyName("originalUserName")]
222 public string OriginalUserName { get; set; }
223
224 [JsonPropertyName("accessToken")]
225 public string AccessToken { get; set; }
226
227 [JsonPropertyName("refreshToken")]
228 public string RefreshToken { get; set; }
229 [JsonPropertyName("head")]
230 public object Head { get; set; }
231 }
232
233 public class RefreshTokenRequest
234 {
235 [JsonPropertyName("refreshToken")]
236 public string RefreshToken { get; set; }
237 }
238
239 public class ImpersonationRequest
240 {
241 [JsonPropertyName("userName")]
242 public string UserName { get; set; }
243 }
244}
245
Note: See TracBrowser for help on using the repository browser.