All checks were successful
Build and Deploy API / build-and-deploy (push) Successful in 8s
112 lines
3.5 KiB
C#
112 lines
3.5 KiB
C#
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Identity;
|
|
|
|
using agologumApi.Models;
|
|
using agologumApi.Services;
|
|
|
|
[ApiController]
|
|
[Route("api/[controller]")]
|
|
public class AuthController : ControllerBase {
|
|
|
|
// identity things
|
|
private readonly UserManager<User> userManager_;
|
|
private readonly SignInManager<User> signInManager_;
|
|
|
|
private readonly JwtService jwt_;
|
|
|
|
public AuthController(UserManager<User> userManager, SignInManager<User> signInManager, JwtService jwt) {
|
|
|
|
userManager_ = userManager;
|
|
signInManager_ = signInManager;
|
|
jwt_ = jwt;
|
|
}
|
|
|
|
[HttpPost("register")]
|
|
public async Task<ActionResult> Register(RegisterDto dto) {
|
|
var user = new User {
|
|
UserName = dto.UserName,
|
|
Email = dto.Email,
|
|
CreatedAt = DateTime.UtcNow // yeah why not utc
|
|
};
|
|
|
|
var result = await userManager_.CreateAsync(user, dto.Password);
|
|
if(!result.Succeeded) return BadRequest(result.Errors);
|
|
|
|
return CreatedAtAction(
|
|
nameof(Register),
|
|
new { id = user.Id }
|
|
);
|
|
}
|
|
|
|
[HttpPost("login")]
|
|
public async Task<ActionResult> Login(LoginDto dto)
|
|
{
|
|
var user = await userManager_.FindByNameAsync(dto.UserName);
|
|
|
|
if (user == null) return Unauthorized();
|
|
|
|
var result = await signInManager_.CheckPasswordSignInAsync(user, dto.Password, false);
|
|
|
|
if(!result.Succeeded) return Unauthorized();
|
|
|
|
var accessToken = jwt_.GenerateJwt(user);
|
|
var refreshToken = jwt_.GenerateRefreshToken();
|
|
RefreshToken newTokenObject = new RefreshToken {
|
|
Token = refreshToken,
|
|
UserId = user.Id,
|
|
CreatedAt = DateTime.UtcNow,
|
|
ExpiresAt = DateTime.UtcNow.AddDays(30),
|
|
IsRevoked = false
|
|
};
|
|
await jwt_.AddRefreshToken(newTokenObject);
|
|
|
|
return Ok(new { accessToken, refreshToken });
|
|
}
|
|
|
|
[Authorize] // authorize is handled by middleware
|
|
[HttpPost("logout")]
|
|
public async Task<ActionResult> Logout(string refreshTokenString) {
|
|
// revoke refresh token
|
|
bool success = await jwt_.RevokeRefreshToken(refreshTokenString);
|
|
if(!success) return NotFound();
|
|
return Ok();
|
|
}
|
|
|
|
[HttpPost("refresh")] // allow-anonymous by default
|
|
public async Task<ActionResult> Refresh(TokenDto request) {
|
|
|
|
RefreshToken? storedToken = await jwt_.GetRefreshToken(request.RefreshToken);
|
|
if (storedToken == null) return Unauthorized();
|
|
bool valid = (storedToken.IsRevoked) ||
|
|
(storedToken.ExpiresAt < DateTime.UtcNow);
|
|
if(!valid) return Unauthorized(); // TODO: delete the invalid token
|
|
|
|
User? user = await jwt_.GetUser(storedToken.UserId);
|
|
if(user == null) return NotFound();
|
|
string? newAccessToken = jwt_.GenerateJwt(user);
|
|
if(newAccessToken == null) return NotFound();
|
|
string newRefreshToken = jwt_.GenerateRefreshToken();
|
|
|
|
storedToken.IsRevoked = true;
|
|
RefreshToken newTokenObject = new RefreshToken {
|
|
Token = newRefreshToken,
|
|
UserId = storedToken.UserId,
|
|
CreatedAt = DateTime.UtcNow,
|
|
ExpiresAt = DateTime.UtcNow.AddDays(30),
|
|
IsRevoked = false
|
|
};
|
|
|
|
await jwt_.AddRefreshToken(newTokenObject);
|
|
|
|
return Ok(new { accessToken = newAccessToken, refreshToken = newRefreshToken });
|
|
|
|
|
|
}
|
|
|
|
// TODO
|
|
// email verification
|
|
// password reset
|
|
// oh hell naw 2FA I do not care enough
|
|
} |