using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using IdentityModel; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using xCommons.Constants; using xCommons.Extensions; using xExceptions.Constants; using xIdentityModels; using xIdentityModels.Constants; using xIdentityModels.Dtos; using xIdentityModels.Extensions; using xIdentityModels.Navigations; namespace xIds.Providers { public partial class XIdentityManager { // #region User Handlers ... /// /// Check a User Exists or not /// /// specified user's identifier /// a boolean value public async Task IsUserExistsAsync( string userSelectByParam ) { // // Validate Args ... if (userSelectByParam.IsNullOrEmpty()) { return false; } // var selectType = GetUserSelectByType(userSelectByParam); // var result = false; XUser user = null; switch (selectType) { case XUserSelectBy.MobileNumber: user = await GetUsersDbSet() .Where(ur => ur.PhoneNumber == userSelectByParam) .FirstOrDefaultAsync(); break; case XUserSelectBy.Email: user = await UserManager .FindByEmailAsync(userSelectByParam); break; case XUserSelectBy.Username: user = await UserManager .FindByNameAsync(userSelectByParam); break; case XUserSelectBy.ID: default: user = await UserManager .FindByIdAsync(userSelectByParam); break; } // result = user != null; // return result; } /// /// Check a User Selector is Available for Registration or Not /// /// specified user's identifier /// a boolean value public async Task CanRegister( string userSelectByParam ) { // // Validate ARgs ... ValidationProvider.NotEmpty(userSelectByParam); // var selectByType = GetUserSelectByType(userSelectByParam); // if (selectByType == XUserSelectBy.Username && !ValidateUserName(userSelectByParam)) { return false; } // var isExists = await IsUserExistsAsync(userSelectByParam); if (isExists) { return false; } // return true; } /// /// Get a User object /// /// specified user's identifier /// specifies returned object contains all Navigation Properties or not, default is false /// an instance of XUser public async Task GetUserAsync( string userSelectByParam, bool containDetails = false ) { // var isExists = await IsUserExistsAsync(userSelectByParam); if (!isExists) { XException.NotFound.Throw(); } // // Fill User ... var selectType = GetUserSelectByType(userSelectByParam); XUser user = null; var usersStore = GetUsersDbSet(containDetails); // // Select Type ... switch (selectType) { case XUserSelectBy.MobileNumber: user = await usersStore .FirstOrDefaultAsync(ur => ur.PhoneNumber == userSelectByParam); break; case XUserSelectBy.Email: user = await usersStore .FirstOrDefaultAsync(ur => ur.Email == userSelectByParam); break; case XUserSelectBy.Username: user = await usersStore .FirstOrDefaultAsync(ur => ur.UserName == userSelectByParam); break; case XUserSelectBy.ID: default: user = await usersStore .FirstOrDefaultAsync(ur => ur.Id == userSelectByParam); break; } // return user; } /// /// Retrieve User Names based on UserIds /// /// a collection of user identifiers /// a collection of Usernames public async Task> GetUserNamesAsync( IEnumerable userIds ) { // // Validate Args ... if (userIds == null || userIds.Count() == 0) { return null; } // var result = await GetUsersDbSet() .Where( xu => userIds .Contains(xu.Id)) .Select(xt => xt.UserName) .ToListAsync(); // return result; } /// /// get user ids and retrieve corresponding user names /// /// an instance of XUserNameIdRequest which represent required UserIds collection /// a collection of XUserNameIdResponse instances public async Task> GetUserNameIdsAsync( XUserNameIdRequest model ) { // // Validate Args ... if (model.IsNull() || !model.Ids.HasChild()) { return null; } // var result = await GetUsersDbSet() .Where( xu => model.Ids.Contains(xu.Id) || model.Ids.Contains(xu.Email) || model.Ids.Contains(xu.UserName) || model.Ids.Contains(xu.PhoneNumber)) .Select(xt => new XUserNameIdResponse { Id = xt.Id, UserName = xt.UserName, }) .ToListAsync(); // return result; } /// /// Create a User /// /// an instance of XUser /// user's password /// check a user can log in in system or not, default is false /// check user is banned or not, default is false /// an instance of IdentityResult public async Task CreateUserAsync( XUser user, string password, bool checkCanLoginPolicies = false, bool checkIsBanned = false ) { // if (user == null || password.IsNullOrEmpty()) { XException.InvalidArgs.Throw(); } // // Get User Select By param var userSelectByParam = GetUserSelectByParam(user, excludes: new List { XUserSelectBy.ID }); // // Check User Created before or not ... var isExists = await IsUserExistsAsync(userSelectByParam); if (isExists) { XException.Duplicate.Throw(); } // var result = await UserManager.CreateAsync(user, password); if (result.Succeeded) { // var claims = await ToJwtClaims( user, checkCanLoginPolicies: checkCanLoginPolicies, checkIsBanned: checkIsBanned); // var addClaimsResult = await UserManager.AddClaimsAsync(user, claims); // return addClaimsResult; } // return result; } /// /// Update a User Information /// /// an instance of XUser /// check a user can log in in system or not, default is true /// check user is banned or not, default is true /// an instance of IdentityResult public async Task UpdateUserAsync( XUser user, bool checkCanLoginPolicies = true, bool checkIsBanned = true ) { // var updateResult = await this.UserManager.UpdateAsync(user); if (updateResult.Succeeded) { // var claims = await ToJwtClaims( user, checkCanLoginPolicies: checkCanLoginPolicies, checkIsBanned: checkIsBanned ); var existsClaims = await UserManager.GetClaimsAsync(user); // await UserManager.RemoveClaimsAsync(user, existsClaims); var addClaimsResult = await UserManager.AddClaimsAsync(user, claims); // return addClaimsResult; } // return updateResult; } /// /// Generate JWT Claims froma DashboardUser object /// /// an instance of XUser /// check a user can log in in system or not, default is true /// check user is banned or not, default is true /// a collection of Claim instances public async Task ToJwtClaims( XUser user, bool checkCanLoginPolicies = true, bool checkIsBanned = true ) { // // Get New Instance of Claims ... var claims = new List { // // Mapping to User.Identity.Name ... new Claim (JwtClaimTypes.Name, user.UserName), // // Mapping to User.Identity.Name ... new Claim (JwtRegisteredClaimNames.UniqueName, user.UserName), // // Other Usefull User Related Data ... new Claim (JwtClaimTypes.GivenName, user.FirstName), new Claim (JwtClaimTypes.FamilyName, user.LastName), // // User Gendre ... new Claim (JwtClaimTypes.Gender, user.Gender.ToString (), ClaimValueTypes.Integer), // // User Profile Picture ... new Claim (JwtClaimTypes.Picture, !user.Avatar.IsNullOrEmpty () ? user.Avatar.ToString () : ""), // // The Unique Identifier for Each Token ... new Claim (JwtRegisteredClaimNames.Jti, Guid.NewGuid ().ToString ()), // // Add isEnable and isBanned feature ... new Claim ( XCustomClaims.IsEnabled, user.IsEnable.ToString (), ClaimValueTypes.Boolean ), new Claim ( XCustomClaims.IsBanned, user.IsBanned.ToString (), ClaimValueTypes.Boolean ), }; // #region Set Claims based on Profile Policies ... // if (Configuration.Policy.Profile.ContainsDateOfBirth) { claims.Add(new Claim(JwtRegisteredClaimNames.Birthdate, user.DateOfBirth.ToString())); } // if (Configuration.Policy.Profile.ContainsEmail) { claims.Add(new Claim(JwtClaimTypes.Email, user.Email)); claims.Add(new Claim( JwtClaimTypes.EmailVerified, user.EmailConfirmed.ToString(), ClaimValueTypes.Boolean)); } // if (Configuration.Policy.Profile.ContainsPhoneNumber) { claims.Add(new Claim(JwtClaimTypes.PhoneNumber, user.PhoneNumber)); claims.Add(new Claim( JwtClaimTypes.PhoneNumberVerified, user.PhoneNumberConfirmed.ToString(), ClaimValueTypes.Boolean)); } // if (Configuration.Policy.Profile.ContainsRoles) { var roleNames = await GetRoleNamesAsync( user.UserName, checkCanLoginPolicies: checkCanLoginPolicies, checkIsBanned: checkIsBanned); roleNames.ToList() .ForEach(rn => { claims.Add(new Claim(JwtClaimTypes.Role, rn)); }); } // if (Configuration.Policy.Profile.ContainsLastLogin) { claims.Add(new Claim( JwtClaimTypes.AuthenticationTime, user.LastLogin.ToString(), ClaimValueTypes.DateTime)); } #endregion // // Return Result ... return claims.ToArray(); } /// /// Check User and Password relation /// /// an instance of XUser /// user's password /// an instance of XDevice /// specify destination language /// specify account lockout on failure log in /// specify log in force without checking XDevice and lang relation /// an instance of SignInResult public async Task CheckPasswordSignInAsync( XUser user, string password, XDevice device, string language, bool lockoutOnFailure, bool isForced = true ) { // var result = await SignInManager.CheckPasswordSignInAsync( user, password, lockoutOnFailure ); // if (result.Succeeded && isForced) { // var isExistsDevice = user.Devices.Any(d => d.IsSameAs(device)); if (!isExistsDevice && !user.Email.IsNullOrEmpty() && user.EmailConfirmed) { // user.Devices.Add(device); // var updateUserResult = await UpdateUserAsync(user); if (updateUserResult.Succeeded) { // try { // var xMessage = GetUserNewDeviceLoggedInMessage( language, user.Email, device ); // await MessageProvider.SendMailAsync(xMessage); } catch { } } } } // return result; } #endregion } }