Initial ...
This commit is contained in:
@@ -0,0 +1,503 @@
|
||||
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 ...
|
||||
/// <summary>
|
||||
/// Check a User Exists or not
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">specified user's identifier</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public async Task<bool> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a User Selector is Available for Registration or Not
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">specified user's identifier</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public async Task<bool> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a User object
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">specified user's identifier</param>
|
||||
/// <param name="containDetails">specifies returned object contains all Navigation Properties or not, default is false</param>
|
||||
/// <returns>an instance of <see>XUser</see></returns>
|
||||
public async Task<XUser> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve User Names based on UserIds
|
||||
/// </summary>
|
||||
/// <param name="userIds">a collection of user identifiers</param>
|
||||
/// <returns>a collection of Usernames</returns>
|
||||
public async Task<IEnumerable<string>> GetUserNamesAsync(
|
||||
IEnumerable<string> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// get user ids and retrieve corresponding user names
|
||||
/// </summary>
|
||||
/// <param name="model">an instance of <see>XUserNameIdRequest</see> which represent required UserIds collection</param>
|
||||
/// <returns>a collection of <see>XUserNameIdResponse</see> instances</returns>
|
||||
public async Task<IEnumerable<XUserNameIdResponse>> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a User
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <param name="password">user's password</param>
|
||||
/// <param name="checkCanLoginPolicies">check a user can log in in system or not, default is false</param>
|
||||
/// <param name="checkIsBanned">check user is banned or not, default is false</param>
|
||||
/// <returns>an instance of <see>IdentityResult</see></returns>
|
||||
public async Task<IdentityResult> 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> { 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update a User Information
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <param name="checkCanLoginPolicies">check a user can log in in system or not, default is true</param>
|
||||
/// <param name="checkIsBanned">check user is banned or not, default is true</param>
|
||||
/// <returns>an instance of <see>IdentityResult</see></returns>
|
||||
public async Task<IdentityResult> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate JWT Claims froma DashboardUser object
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <param name="checkCanLoginPolicies">check a user can log in in system or not, default is true</param>
|
||||
/// <param name="checkIsBanned">check user is banned or not, default is true</param>
|
||||
/// <returns>a collection of <see>Claim</see> instances</returns>
|
||||
public async Task<Claim[]> ToJwtClaims(
|
||||
XUser user,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
)
|
||||
{
|
||||
//
|
||||
// Get New Instance of Claims ...
|
||||
var claims = new List<Claim> {
|
||||
//
|
||||
// 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check User and Password relation
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <param name="password">user's password</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="language">specify destination language</param>
|
||||
/// <param name="lockoutOnFailure">specify account lockout on failure log in</param>
|
||||
/// <param name="isForced">specify log in force without checking <see>XDevice</see> and lang relation</param>
|
||||
/// <returns>an instance of <see>SignInResult</see></returns>
|
||||
public async Task<SignInResult> 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user