source: iknow-api/Services/Implementations/AuthService.cs@ ea40556

Last change on this file since ea40556 was ea40556, checked in by Stefan-Saveski <stefansaveski19@…>, 8 days ago
  • ready for presentation
  • Property mode set to 100644
File size: 6.7 KB
Line 
1using System.IdentityModel.Tokens.Jwt;
2using System.Security.Claims;
3using System.Text;
4using BCrypt.Net;
5using iknow_api.Models;
6using iknow_api.DTOs;
7using iknow_api.Repositories;
8using Microsoft.IdentityModel.Tokens;
9using iknow_api.Data;
10
11namespace iknow_api.Services
12{
13 public class AuthService : IAuthService
14 {
15 private readonly IUserRepository _userRepository;
16 private readonly IRefreshTokenRepository _refreshTokenRepository;
17 private readonly IRefreshTokenService _refreshTokenService;
18 private readonly IConfiguration _configuration;
19 private readonly AppDbContext _context;
20
21 public AuthService(IUserRepository userRepository, IConfiguration configuration,
22 IRefreshTokenService refreshTokenService, IRefreshTokenRepository refreshTokenRepository,
23 AppDbContext context)
24 {
25 _userRepository = userRepository;
26 _configuration = configuration;
27 _refreshTokenService = refreshTokenService;
28 _refreshTokenRepository = refreshTokenRepository;
29 _context = context;
30 }
31
32 public async Task<bool> RegisterAsync(RegisterDto registerDto)
33 {
34 // Debug: Log all incoming DTO values
35 Console.WriteLine("=== RegisterDto Debug Info ===");
36 Console.WriteLine($"Name: {registerDto.Name}");
37 Console.WriteLine($"Email: {registerDto.Email}");
38 Console.WriteLine($"majorType: {registerDto.majorType}");
39 Console.WriteLine($"enrollmentYear: {registerDto.enrollmentYear}");
40 Console.WriteLine($"quotaType: {registerDto.quotaType}");
41 Console.WriteLine($"Role: {registerDto.Role}");
42 Console.WriteLine($"tip: {registerDto.tip}");
43 Console.WriteLine("==============================");
44
45 // Check if user already exists
46 if (await _userRepository.UserExistsAsync(registerDto.Email))
47 throw new InvalidOperationException("User with this email already exists");
48
49 // Use a transaction to ensure all entities are saved together
50 using var transaction = await _context.Database.BeginTransactionAsync();
51 try
52 {
53 // quota and enrollment_year are attributes of Users in the ER
54 // model, so they are set here rather than on a separate entity.
55 var user = new User
56 {
57 Name = registerDto.Name,
58 Surname = registerDto.Surname,
59 Index = registerDto.Index,
60 Email = registerDto.Email,
61 PasswordHash = BCrypt.Net.BCrypt.HashPassword(registerDto.Password),
62 Bday = DateTime.SpecifyKind(registerDto.Bday, DateTimeKind.Unspecified),
63 CreatedAt = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified),
64 Role = (Models.UserRole)registerDto.Role,
65 EMBG = registerDto.EMBG,
66 Quota = (Models.Quota)registerDto.quotaType,
67 EnrollmentYear = registerDto.enrollmentYear
68 };
69
70 _context.User.Add(user);
71 await _context.SaveChangesAsync();
72
73 int userId = user.Id;
74
75 var contactInfo = new ContactInfo
76 {
77 UserId = userId,
78 City = registerDto.city,
79 Address = registerDto.address,
80 Municipality = registerDto.municipality,
81 PhoneNumber = registerDto.phoneNumber,
82 MicrosoftEmail = registerDto.microsoftEmail
83 };
84
85 var highSchool = new HighSchool
86 {
87 UserId = userId,
88 GPA = registerDto.gpa,
89 HighSchoolType = (Models.HighSchoolType)registerDto.tip
90 };
91
92 _context.ContactInfo.Add(contactInfo);
93 _context.HighSchool.Add(highSchool);
94
95 // Save all related entities in a single transaction
96 await _context.SaveChangesAsync();
97 await transaction.CommitAsync();
98
99 return true;
100 }
101 catch
102 {
103 await transaction.RollbackAsync();
104 throw;
105 }
106 }
107
108 public async Task<AuthResultDto?> LoginAsync(LoginDto loginDto)
109 {
110 var user = await _userRepository.GetUserByUsernameAsync(loginDto.Email);
111 if (user == null || !BCrypt.Net.BCrypt.Verify(loginDto.Password, user.PasswordHash))
112 return null;
113
114 var result = new AuthResultDto
115 {
116 AccessToken = CreateToken(user),
117 Role = user.Role.ToString()
118 };
119
120 if (loginDto.GenerateRefreshToken)
121 {
122 result.RefreshToken = await _refreshTokenService.GenerateRefreshToken(user.Id);
123 }
124
125 return result;
126 }
127
128 public async Task<int> GetUsersCountAsync()
129 {
130 return await _userRepository.GetUsersCountAsync();
131 }
132
133 public async Task<AuthResultDto> GenerateNewJWT(VerifyRefreshTokenDto token)
134 {
135 int userid = await _refreshTokenRepository.GetUserId(token.token) ?? 0;
136 User? user = await _userRepository.GetOnlyUserByIdAsync(userid);
137
138 if (user == null)
139 throw new InvalidOperationException("User not found for provided refresh token.");
140
141 return new AuthResultDto
142 {
143 AccessToken = CreateToken(user),
144 Role = user.Role.ToString()
145 };
146 }
147
148 private string CreateToken(User user)
149 {
150 var claims = new[]
151 {
152 new Claim("id", user.Id.ToString()),
153 new Claim("email", user.Email ?? string.Empty),
154 new Claim("role", user.Role.ToString())
155 };
156
157 var keyString = _configuration["Jwt:Key"];
158 if (string.IsNullOrEmpty(keyString))
159 throw new Exception("JWT Key is missing in configuration!");
160
161 var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(keyString));
162 var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
163
164 var jwt = new JwtSecurityToken(
165 issuer: "iknow-api",
166 audience: "iknow-api",
167 claims: claims,
168 expires: DateTime.UtcNow.AddHours(1),
169 signingCredentials: creds
170 );
171
172 return new JwtSecurityTokenHandler().WriteToken(jwt);
173 }
174 }
175}
Note: See TracBrowser for help on using the repository browser.