moved database primary keys to guids

This commit is contained in:
2026-02-20 20:24:57 -08:00
parent b7a78b7bb9
commit da4320f26e
14 changed files with 58 additions and 50 deletions
+3 -3
View File
@@ -5,14 +5,14 @@ namespace WinStudentGoalTracker.BaseClasses;
public class BaseController : ControllerBase
{
protected (int userId, ActionResult? error) GetUserIdFromClaims()
protected (Guid userId, ActionResult? error) GetUserIdFromClaims()
{
var userIdClaim = User.FindFirst("user_id")?.Value
?? User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (string.IsNullOrWhiteSpace(userIdClaim) || !int.TryParse(userIdClaim, out var userId))
if (string.IsNullOrWhiteSpace(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId))
{
return (0, Unauthorized("Missing or invalid user_id claim."));
return (Guid.Empty, Unauthorized("Missing or invalid user_id claim."));
}
return (userId, null);
+4 -2
View File
@@ -87,6 +87,7 @@ public class AuthController : BaseController
// Store refresh token in database (30 days expiration)
var refreshTokenId = await _authRepo.CreateRefreshTokenAsync(
Guid.NewGuid(),
user.IdUser,
refreshTokenHash,
refreshTokenSalt,
@@ -151,7 +152,7 @@ public class AuthController : BaseController
var tokenIdStr = refreshTokenDto.RefreshToken[..dotIndex];
var secretToken = refreshTokenDto.RefreshToken[(dotIndex + 1)..];
if (!int.TryParse(tokenIdStr, out int tokenId))
if (!Guid.TryParse(tokenIdStr, out Guid tokenId))
{
return BadRequest(new ResponseResult<TokenRefreshResponse>
{
@@ -221,6 +222,7 @@ public class AuthController : BaseController
var newRefreshTokenId = await _authRepo.ReplaceRefreshTokenAsync(
matchedToken.IdRefreshToken,
Guid.NewGuid(),
tokenUser.IdUser,
newRefreshTokenHash,
newRefreshTokenSalt,
@@ -272,7 +274,7 @@ public class AuthController : BaseController
if (error != null) return error;
var dotIndex = logoutDto.RefreshToken.IndexOf('.');
if (dotIndex < 1 || !int.TryParse(logoutDto.RefreshToken[..dotIndex], out int tokenId))
if (dotIndex < 1 || !Guid.TryParse(logoutDto.RefreshToken[..dotIndex], out Guid tokenId))
{
return BadRequest(new ResponseResult<object>
{
+6 -6
View File
@@ -29,10 +29,10 @@ public class StudentController : BaseController
});
}
[HttpGet("{idStudent:int}")]
[HttpGet("{idStudent:guid}")]
[ProducesResponseType(typeof(ResponseResult<StudentResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ResponseResult<StudentResponse>), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ResponseResult<StudentResponse>>> GetById(int idStudent)
public async Task<ActionResult<ResponseResult<StudentResponse>>> GetById(Guid idStudent)
{
var student = await _studentRepository.GetByIdAsync(idStudent);
if (student is null)
@@ -84,10 +84,10 @@ public class StudentController : BaseController
});
}
[HttpPut("{idStudent:int}")]
[HttpPut("{idStudent:guid}")]
[ProducesResponseType(typeof(ResponseResult<StudentResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ResponseResult<StudentResponse>), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ResponseResult<StudentResponse>>> Update(int idStudent, [FromBody] UpdateStudentDto request)
public async Task<ActionResult<ResponseResult<StudentResponse>>> Update(Guid idStudent, [FromBody] UpdateStudentDto request)
{
var existing = await _studentRepository.GetByIdAsync(idStudent);
if (existing is null)
@@ -118,10 +118,10 @@ public class StudentController : BaseController
});
}
[HttpDelete("{idStudent:int}")]
[HttpDelete("{idStudent:guid}")]
[ProducesResponseType(typeof(ResponseResult<object>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ResponseResult<object>), StatusCodes.Status404NotFound)]
public async Task<ActionResult<ResponseResult<object>>> Delete(int idStudent)
public async Task<ActionResult<ResponseResult<object>>> Delete(Guid idStudent)
{
var deleted = await _studentRepository.DeleteAsync(idStudent);
if (!deleted)
@@ -2,8 +2,8 @@ namespace WinStudentGoalTracker.DataAccess;
public class CreateStudentDto
{
public required int IdStudent { get; set; }
public int? IdProgram { get; set; }
public required Guid IdStudent { get; set; }
public Guid? IdProgram { get; set; }
public string? Identifier { get; set; }
public int? ProgramYear { get; set; }
public DateTime? EnrollmentDate { get; set; }
@@ -2,7 +2,7 @@ namespace WinStudentGoalTracker.DataAccess;
public class UpdateStudentDto
{
public int? IdProgram { get; set; }
public Guid? IdProgram { get; set; }
public string? Identifier { get; set; }
public int? ProgramYear { get; set; }
public DateTime? EnrollmentDate { get; set; }
@@ -2,8 +2,8 @@ namespace WinStudentGoalTracker.DataAccess;
public class dbRefreshToken
{
public int IdRefreshToken { get; set; }
public int IdUser { get; set; }
public Guid IdRefreshToken { get; set; }
public Guid IdUser { get; set; }
public required string TokenHash { get; set; }
public required string TokenSalt { get; set; }
public DateTime ExpiresAt { get; set; }
@@ -11,7 +11,7 @@ public class dbRefreshToken
public DateTime? RevokedAt { get; set; }
public string? DeviceInfo { get; set; }
public string? UserAgent { get; set; }
public int? ReplacedByTokenId { get; set; }
public Guid? ReplacedByTokenId { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
@@ -2,8 +2,8 @@ namespace WinStudentGoalTracker.DataAccess;
public class dbStudent
{
public required int IdStudent { get; set; }
public int? IdProgram { get; set; }
public required Guid IdStudent { get; set; }
public Guid? IdProgram { get; set; }
public string? Identifier { get; set; }
public int? ProgramYear { get; set; }
public DateTime? EnrollmentDate { get; set; }
@@ -2,8 +2,8 @@ namespace WinStudentGoalTracker.DataAccess;
public class dbUser
{
public required int IdUser { get; set; }
public int? IdRole { get; set; }
public required Guid IdUser { get; set; }
public Guid? IdRole { get; set; }
public string? Email { get; set; }
public string? Name { get; set; }
public string? PasswordHash { get; set; }
@@ -8,8 +8,9 @@ public class AuthRepository
{
private IDbConnection Connection => new MySqlConnection(DatabaseManager.ConnectionString);
public async Task<int?> CreateRefreshTokenAsync(
int userId,
public async Task<Guid?> CreateRefreshTokenAsync(
Guid refreshTokenId,
Guid userId,
string tokenHash,
string tokenSalt,
int expiresInSeconds,
@@ -17,11 +18,12 @@ public class AuthRepository
string? userAgent)
{
using var db = Connection;
return await db.QuerySingleOrDefaultAsync<int?>(
var result = await db.QuerySingleOrDefaultAsync<string?>(
"sp_RefreshToken_Create",
new
{
p_id_user = userId,
p_id_refresh_token = refreshTokenId.ToString(),
p_id_user = userId.ToString(),
p_token_hash = tokenHash,
p_token_salt = tokenSalt,
p_expires_in_seconds = expiresInSeconds,
@@ -29,30 +31,32 @@ public class AuthRepository
p_user_agent = userAgent
},
commandType: CommandType.StoredProcedure);
return result != null ? Guid.Parse(result) : null;
}
public async Task<dbRefreshToken?> GetRefreshTokenByIdAsync(int refreshTokenId)
public async Task<dbRefreshToken?> GetRefreshTokenByIdAsync(Guid refreshTokenId)
{
using var db = Connection;
return await db.QuerySingleOrDefaultAsync<dbRefreshToken>(
"sp_RefreshToken_GetById",
new { p_id_refresh_token = refreshTokenId },
new { p_id_refresh_token = refreshTokenId.ToString() },
commandType: CommandType.StoredProcedure);
}
public async Task<bool> RevokeRefreshTokenAsync(int refreshTokenId)
public async Task<bool> RevokeRefreshTokenAsync(Guid refreshTokenId)
{
using var db = Connection;
var rowsAffected = await db.QuerySingleOrDefaultAsync<int>(
"sp_RefreshToken_Revoke",
new { p_id_refresh_token = refreshTokenId },
new { p_id_refresh_token = refreshTokenId.ToString() },
commandType: CommandType.StoredProcedure);
return rowsAffected > 0;
}
public async Task<int?> ReplaceRefreshTokenAsync(
int oldTokenId,
int userId,
public async Task<Guid?> ReplaceRefreshTokenAsync(
Guid oldTokenId,
Guid newTokenId,
Guid userId,
string tokenHash,
string tokenSalt,
int expiresInSeconds,
@@ -60,12 +64,13 @@ public class AuthRepository
string? userAgent)
{
using var db = Connection;
return await db.QuerySingleOrDefaultAsync<int?>(
var result = await db.QuerySingleOrDefaultAsync<string?>(
"sp_RefreshToken_Replace",
new
{
p_old_token_id = oldTokenId,
p_id_user = userId,
p_old_token_id = oldTokenId.ToString(),
p_id_refresh_token = newTokenId.ToString(),
p_id_user = userId.ToString(),
p_token_hash = tokenHash,
p_token_salt = tokenSalt,
p_expires_in_seconds = expiresInSeconds,
@@ -73,5 +78,6 @@ public class AuthRepository
p_user_agent = userAgent
},
commandType: CommandType.StoredProcedure);
return result != null ? Guid.Parse(result) : null;
}
}
@@ -16,12 +16,12 @@ public class StudentRepository
commandType: CommandType.StoredProcedure);
}
public async Task<dbStudent?> GetByIdAsync(int idStudent)
public async Task<dbStudent?> GetByIdAsync(Guid idStudent)
{
using var db = Connection;
return await db.QuerySingleOrDefaultAsync<dbStudent>(
"sp_Student_GetById",
new { p_id_student = idStudent },
new { p_id_student = idStudent.ToString() },
commandType: CommandType.StoredProcedure);
}
@@ -32,8 +32,8 @@ public class StudentRepository
"sp_Student_Insert",
new
{
p_id_student = dto.IdStudent,
p_id_program = dto.IdProgram,
p_id_student = dto.IdStudent.ToString(),
p_id_program = dto.IdProgram?.ToString(),
p_identifier = dto.Identifier,
p_program_year = dto.ProgramYear,
p_enrollment_date = dto.EnrollmentDate,
@@ -42,15 +42,15 @@ public class StudentRepository
commandType: CommandType.StoredProcedure);
}
public async Task<bool> UpdateAsync(int idStudent, UpdateStudentDto dto)
public async Task<bool> UpdateAsync(Guid idStudent, UpdateStudentDto dto)
{
using var db = Connection;
var rowsAffected = await db.ExecuteScalarAsync<int>(
"sp_Student_Update",
new
{
p_id_student = idStudent,
p_id_program = dto.IdProgram,
p_id_student = idStudent.ToString(),
p_id_program = dto.IdProgram?.ToString(),
p_identifier = dto.Identifier,
p_program_year = dto.ProgramYear,
p_enrollment_date = dto.EnrollmentDate,
@@ -60,12 +60,12 @@ public class StudentRepository
return rowsAffected > 0;
}
public async Task<bool> DeleteAsync(int idStudent)
public async Task<bool> DeleteAsync(Guid idStudent)
{
using var db = Connection;
var rowsAffected = await db.ExecuteScalarAsync<int>(
"sp_Student_Delete",
new { p_id_student = idStudent },
new { p_id_student = idStudent.ToString() },
commandType: CommandType.StoredProcedure);
return rowsAffected > 0;
}
@@ -17,12 +17,12 @@ public class UserRepository
commandType: CommandType.StoredProcedure);
}
public async Task<dbUser?> GetByIdAsync(int idUser)
public async Task<dbUser?> GetByIdAsync(Guid idUser)
{
using var db = Connection;
return await db.QuerySingleOrDefaultAsync<dbUser>(
"sp_User_GetById",
new { p_id_user = idUser },
new { p_id_user = idUser.ToString() },
commandType: CommandType.StoredProcedure);
}
}
@@ -2,7 +2,7 @@ namespace WinStudentGoalTracker.Models;
public class LoginResponse
{
public int UserId { get; set; }
public Guid UserId { get; set; }
public required string Email { get; set; }
public required string Jwt { get; set; }
public required string RefreshToken { get; set; }
@@ -4,8 +4,8 @@ namespace WinStudentGoalTracker.Models;
public class StudentResponse
{
public int IdStudent { get; set; }
public int? IdProgram { get; set; }
public Guid IdStudent { get; set; }
public Guid? IdProgram { get; set; }
public string? Identifier { get; set; }
public int? ProgramYear { get; set; }
public DateTime? EnrollmentDate { get; set; }
+1 -1
View File
@@ -15,7 +15,7 @@ public class TokenService
_config = config;
}
public string GenerateToken(int userId, string email, string? roleName)
public string GenerateToken(Guid userId, string email, string? roleName)
{
var claims = new List<Claim>
{