source: resTools_backend/backend/Services/UserService.cs@ a569b7c

Last change on this file since a569b7c was a26f6a1, checked in by Danilo <danilo.najkov@…>, 23 months ago

full auth flow

  • Property mode set to 100644
File size: 5.5 KB
Line 
1namespace backend.Services;
2
3using backend.Data;
4using backend.DTOs;
5using backend.Email;
6using backend.Entities;
7using backend.Helpers;
8using backend.Models;
9using Microsoft.EntityFrameworkCore;
10using Microsoft.Extensions.Options;
11using Microsoft.IdentityModel.Tokens;
12using System.IdentityModel.Tokens.Jwt;
13using System.Security.Claims;
14using System.Security.Cryptography;
15using System.Text;
16
17public interface IUserService
18{
19 Task<AuthenticateResponse> Authenticate(AuthenticateRequest model);
20 Task<AuthenticateResponse> Register(CreateUserRequest req, bool isFirst);
21 Task<User> GetById(int id);
22 Task SendEmailConfirmation(string email);
23 Task SendPasswordReset(string email);
24 Task ConfirmEmail(User user, string checkValid);
25 Task ResetPassword(string checkValid, string password);
26}
27
28public class UserService : IUserService
29{
30 private readonly AppSettings _appSettings;
31 private readonly DataContext _context = null;
32 private readonly IEmailSender _emailSender;
33
34 public UserService(IOptions<AppSettings> appSettings, DataContext context, IEmailSender emailSender)
35 {
36 _appSettings = appSettings.Value;
37 _context = context;
38 _emailSender = emailSender;
39 }
40
41 public async Task<AuthenticateResponse> Authenticate(AuthenticateRequest model)
42 {
43 User user = await _context.Users.FirstOrDefaultAsync(x => x.Email == model.Email && x.Password == model.Password);
44
45 // return null if user not found
46 if (user == null) return null;
47
48 // authentication successful so generate jwt token
49 var token = generateJwtToken(user);
50
51 return new AuthenticateResponse { Email = user.Email, Id = user.Id, Token = token, IsAdmin = user.IsAdmin, IsConfirmed = user.IsConfirmed};
52 }
53
54 public async Task ConfirmEmail(User user, string checkValid)
55 {
56 if(user.ConfirmationURL != checkValid)
57 {
58 throw new Exception("Invalid check");
59 }
60 if(user.ConfirmationValidTo < DateTime.UtcNow)
61 {
62 throw new Exception("Link expired");
63 }
64
65 user.IsConfirmed = true;
66 _context.Users.Update(user);
67 await _context.SaveChangesAsync();
68 }
69
70 public async Task<User> GetById(int id)
71 {
72 return await _context.Users.FindAsync(id);
73 }
74
75 public async Task<AuthenticateResponse> Register(CreateUserRequest req, bool isFirst)
76 {
77 User user = new User() { Email = req.Email, Password = req.Password, IsAdmin = isFirst, IsConfirmed = false };
78 await _context.Users.AddAsync(user);
79 await _context.SaveChangesAsync();
80 var token = generateJwtToken(user);
81 return new AuthenticateResponse { Email = user.Email, Id = user.Id, Token = token, IsAdmin = user.IsAdmin, IsConfirmed = false };
82 }
83
84 public async Task ResetPassword(string checkValid, string password)
85 {
86 var user = await _context.Users.Where(x => x.PasswordResetURL == checkValid).FirstOrDefaultAsync();
87 if (user == null)
88 {
89 throw new Exception("Invalid check");
90 }
91 if (user.PasswordResetValidTo < DateTime.UtcNow)
92 {
93 throw new Exception("Link expired");
94 }
95
96 user.Password = password;
97 _context.Users.Update(user);
98 await _context.SaveChangesAsync();
99 }
100
101 public async Task SendEmailConfirmation(string email)
102 {
103 User user = await _context.Users.FirstOrDefaultAsync(x => x.Email == email);
104 user.ConfirmationURL = Guid.NewGuid().ToString();
105 user.ConfirmationValidTo = DateTime.UtcNow.AddHours(24);
106 _context.Users.Update(user);
107 await _context.SaveChangesAsync();
108 await _emailSender.SendEmailAsync(
109 "Потврдете го вашиот емаил",
110 "Ве молиме кликнете на следниот линк за да го потврдите вашиот емаил: http://localhost:3000/confirm?id=" + user.ConfirmationURL,
111 email);
112 }
113
114 public async Task SendPasswordReset(string email)
115 {
116 User user = await _context.Users.FirstOrDefaultAsync(x => x.Email == email);
117 user.PasswordResetURL = Guid.NewGuid().ToString();
118 user.PasswordResetValidTo = DateTime.UtcNow.AddHours(24);
119 _context.Users.Update(user);
120 await _context.SaveChangesAsync();
121 await _emailSender.SendEmailAsync(
122 "Ресетирајте ја лозинката",
123 "Ве молиме кликнете на следниот линк за да ја ресетирате лозинката: http://localhost:3000/reset?id=" + user.PasswordResetURL,
124 email);
125 }
126
127 private string generateJwtToken(User user)
128 {
129 // generate token that is valid for 7 days
130 var tokenHandler = new JwtSecurityTokenHandler();
131 var key = System.Text.Encoding.ASCII.GetBytes(_appSettings.Secret);
132 var tokenDescriptor = new SecurityTokenDescriptor
133 {
134 Subject = new ClaimsIdentity(new[] { new Claim("id", user.Id.ToString()) }),
135 Expires = DateTime.UtcNow.AddDays(7),
136 SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
137 };
138 var token = tokenHandler.CreateToken(tokenDescriptor);
139 return tokenHandler.WriteToken(token);
140 }
141
142 private string sha256Hash(String value)
143 {
144 using (SHA256 hash = SHA256.Create())
145 {
146 return String.Concat(hash
147 .ComputeHash(Encoding.UTF8.GetBytes(value))
148 .Select(item => item.ToString("x2")));
149 }
150 }
151}
Note: See TracBrowser for help on using the repository browser.