using Domain.Identity; using Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Models.Identity; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Services.Identity { public class AuthService : BaseService, IAuthService { private readonly ITokenIssuer _tokenIssuer; public AuthService(IServiceProvider serviceProvider) : base(serviceProvider) { _tokenIssuer = serviceProvider.GetService(); } public async Task GetByLoginToken(string username, string token) { var now = DateTime.Now; var loginToken = await _db.LoginTokens .Where(x => !x.Used && x.ExpireationDate > now) .Where(x => x.Token.ToLower() == token.ToLower()) .Where(x => x.Account.Username.ToLower() == username.ToLower()) .Include(x => x.Account).FirstOrDefaultAsync(); if (loginToken is null) return null; var account = loginToken.Account; return account; } public async Task<(Account account, RefreshToken refreshToken)> GetByRefreshToken(string token) { var refreshToken = await _db.RefreshTokens .Include(x => x.LoginToken).ThenInclude(x => x.Account) .FirstOrDefaultAsync(x => x.Token.ToLower().Trim() == token.Trim().ToLower()); if (refreshToken is null) return (null, null); return (refreshToken.LoginToken.Account, refreshToken); } public Account GetByUsername(string username) { return GetQueryable().FirstOrDefault(x => x.Username.ToLower().Trim() == username.ToLower().Trim()); } public async Task GetByUsernameAndPassword(string username, string password) { return GetQueryable(). Where(x => x.Username.Equals(username) && x.Password.Equals(password)).Include(x => x.AccountRoles).FirstOrDefault(); } public async Task GenerateLoginToken(Account account) { var now = DateTime.Now; var token = _db.LoginTokens.FirstOrDefault(x => x.AccountId == account.Id && !x.Used && x.ExpireationDate > now); if (token == null) { var code = RandomGenerator.GetRandomString(4); token = new LoginToken { AccountId = account.Id, ExpireationDate = DateTime.Now.AddMinutes(2), Token = code }; await _db.LoginTokens.AddAsync(token); SaveChanges(); } return token; } public async Task GenerateRefreshToken(LoginToken loginToken) { if (loginToken.Used) return null; var refreshToken = loginToken.RefreshToken ?? new RefreshToken(); loginToken.Used = true; refreshToken.Token = Guid.NewGuid().ToString(); refreshToken.LoginTokenId = loginToken.Id; if (loginToken.RefreshToken is null) { await _db.RefreshTokens.AddAsync(refreshToken); SaveChanges(); } else { SaveChanges(); } return refreshToken; } public async Task GeneratePlainToken(Guid id, string loginToken) { var account =GetById(id); if (account is null) return null; var token = await _db.LoginTokens .Where(x => x.AccountId == id) .Include(x => x.Account) .ThenInclude(x => x.AccountRoles) .ThenInclude(x => x.Role) .Include(x => x.RefreshToken) .FirstOrDefaultAsync(x => x.Token == loginToken); if (token is null) return null; var refreshToken = await GenerateRefreshToken(token); var plainToken = _tokenIssuer.IssuePlainToken(account); return plainToken; } public async Task GeneratePlainToken(Account account, string loginToken) { var token = await _db.LoginTokens .Where(x => x.AccountId == account.Id) .Where(x => x.Token == loginToken) .Include(x => x.Account) .ThenInclude(x => x.AccountRoles) .ThenInclude(x => x.Role) .Include(x => x.RefreshToken) .FirstOrDefaultAsync(); if (token is null) return null; var refreshToken = await GenerateRefreshToken(token); if (refreshToken is null) return null; var plainToken = _tokenIssuer.IssuePlainToken(account); return plainToken; } public async Task RefreshToken(string token) { var refreshToken = await _db.RefreshTokens .Where(x => x.Token == token) .Include(x => x.LoginToken) .ThenInclude(x => x.Account) .ThenInclude(x => x.AccountRoles) .ThenInclude(x => x.Role) .FirstOrDefaultAsync(); if (refreshToken is null || !refreshToken.LoginToken.Used) return null; refreshToken.Token = Guid.NewGuid().ToString(); SaveChanges(); var plainToken = _tokenIssuer.IssuePlainToken(refreshToken.LoginToken.Account); return plainToken; } public void SetDeveloperUser() { string[] developers = { "09169212241", "09161151186" }; var users = GetQueryable().Where(x => developers.Contains(x.Username)).ToList(); foreach (var user in users) { var role = _db.Roles.FirstOrDefault(x => x.Name == Consts.Developer); if (role != null) { var accountRole = _db.AccountRoles.FirstOrDefault(x => x.RoleId == role.Id && x.AccountId == user.Id); if (accountRole == null) _db.AccountRoles.Add(new AccountRole { AccountId = user.Id, RoleId = role.Id }); SaveChanges(); } } } } public interface IAuthService : IBaseService { Account GetByUsername(string username); Task GetByUsernameAndPassword(string username, string password); Task GetByLoginToken(string username, string token); Task GenerateLoginToken(Account account); Task GenerateRefreshToken(LoginToken loginToken); Task<(Account account, RefreshToken refreshToken)> GetByRefreshToken(string token); Task GeneratePlainToken(Account account, string token); Task RefreshToken(string token); void SetDeveloperUser(); } }