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
}
}