Initial ...
This commit is contained in:
+14
@@ -0,0 +1,14 @@
|
||||
#
|
||||
bin
|
||||
obj
|
||||
|
||||
#
|
||||
Db/*
|
||||
!Db/.gitkeep
|
||||
|
||||
#
|
||||
Migrations/*
|
||||
|
||||
#
|
||||
wwwroot
|
||||
!wwwroot/.gitkeep
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace xIds.Configurations
|
||||
{
|
||||
public class CertificatesConfigurations
|
||||
{
|
||||
public struct CertificateNames
|
||||
{
|
||||
public const string IdentityServerSigning = "IdentityServerSigning";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using xIds.Constants;
|
||||
|
||||
namespace xIds.Configurations
|
||||
{
|
||||
/// <summary>
|
||||
/// Represent Configurations of DataService Module ...
|
||||
/// </summary>
|
||||
public partial class XDataServiceConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Provider Type ...
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public XDbProviders Provider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Connection String which provide Requires Data to Connect to Db Provider ...
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public string ConnectionString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enable Tracking of Entities ...
|
||||
/// Only Used on EFCore ...
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public bool EnableTracking { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Enable Logging Details of Errors ...
|
||||
/// Only Used on EFCore ...
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public bool EnableDetailedErrors { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Enable Logging Sensitive Data ...
|
||||
/// Only Used on EFCore ...
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public bool EnableSensitiveDataLogging { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// this is a way to provide Default Pagination Data on XQuery based requests ...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public PagingConfiguration PagingConfiguration { get; set; } = new PagingConfiguration();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// this is a way to provide Default Pagination Data on XQuery based requests ...
|
||||
/// </summary>
|
||||
public partial class PagingConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Default Page Size ...
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public int DefaultPageSize { get; set; } = XDataServiceConstants.DEFAULT_PAGE_SIZE;
|
||||
|
||||
/// <summary>
|
||||
/// restrict Maximum Page Size ...
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public int MaxAvailablePageSize { get; set; } = XDataServiceConstants.MAX_AVAILABLE_PAGE_SIZE;
|
||||
|
||||
/// <summary>
|
||||
/// restrice Minimum Page Size ...
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public int MinAvailablePageSize { get; set; } = XDataServiceConstants.MIN_AVAILABLE_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace xIds.Configurations
|
||||
{
|
||||
/// <summary>
|
||||
/// determines a resource and it's connection info
|
||||
/// </summary>
|
||||
public partial class XIdentityResourceConfiguration
|
||||
{
|
||||
public string Authority { get; set; }
|
||||
public string ApiName { get; set; }
|
||||
public string ApiSecret { get; set; }
|
||||
|
||||
public string ClientId { get; set; }
|
||||
public string ClientSecret { get; set; }
|
||||
|
||||
public string XPoweredValue { get; set; }
|
||||
public string XRevisionSecretKey { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace xIds.Constants
|
||||
{
|
||||
public struct ConfigurationNodeNames
|
||||
{
|
||||
public const string DB_SEED_NODE_NAME = "DbSeeder";
|
||||
public const string PROVIDER_NODE_NAME = "DbProvider";
|
||||
public const string IDENTITY_NODE_NAME = "IdentityConfiguration";
|
||||
public const string DATA_SERVICE_NODE_NAME = "DataServiceConfiguration";
|
||||
public const string IDENTITY_RESOURCE_NODE_NAME = "IdentityResourceConfiguration";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace xIds.Constants
|
||||
{
|
||||
public struct ConnectionStringNames
|
||||
{
|
||||
public const string IDENTITY_CONNECTION_NAME = "IdentityDb";
|
||||
public const string CONFIGURATION_CONNECTION_NAME = "ConfigurationDb";
|
||||
public const string PRESISTED_GRANTS_CONNECTION_NAME = "PersistedGrantDb";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace xIds.Constants
|
||||
{
|
||||
public struct IdentityMessagesKeys
|
||||
{
|
||||
public const string Terms = "terms";
|
||||
public const string InviteMsg = "user_invite_msg";
|
||||
public const string RegistrationApproveMsg = "registration_approve_msg";
|
||||
public const string RegisteredMsg = "registered_msg";
|
||||
public const string VerificationCodeMsg = "verification_code_msg";
|
||||
public const string ChangePasswordMsg = "change_password_msg";
|
||||
public const string PasswordChangedMsg = "password_changed_msg";
|
||||
public const string NewDeviceLoggedInMsg = "new_device_logged_in_msg";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace xIds.Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// /// Default Pagination Values ...
|
||||
/// </summary>
|
||||
public partial struct XDataServiceConstants
|
||||
{
|
||||
public static int DEFAULT_PAGE_SIZE = 50;
|
||||
public static int MAX_AVAILABLE_PAGE_SIZE = 500;
|
||||
public static int MIN_AVAILABLE_PAGE_SIZE = 20;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace xIds.Constants
|
||||
{
|
||||
public partial class XDbProviderConfigurations
|
||||
{
|
||||
/// <summary>
|
||||
/// Default ConnectionString Name ...
|
||||
/// </summary>
|
||||
public const string DEFAULT_CONNECTION_NAME = "DataConnection";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace xIds.Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// /// Represent Supported DBMS for Managing Data ...
|
||||
/// </summary>
|
||||
public enum XDbProviders
|
||||
{
|
||||
None,
|
||||
MySQL,
|
||||
SQLite,
|
||||
SQLServer,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represent Supported DBMS for Managing Data ...
|
||||
/// </summary>
|
||||
public partial struct ProviderType
|
||||
{
|
||||
public const string MySQL = "MYSQL";
|
||||
public const string SQLite = "SQLITE";
|
||||
public const string SQLServer = "SQLSERVER";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using xIdentityHelper;
|
||||
using xCommons.Attributes;
|
||||
using xCommons.Extensions;
|
||||
using xIdentityModels.Dtos;
|
||||
using static IdentityServer4.IdentityServerConstants;
|
||||
|
||||
namespace xIds.Controllers
|
||||
{
|
||||
public partial class AccountController
|
||||
{
|
||||
//
|
||||
#region Admin Actions ...
|
||||
/// <summary>
|
||||
/// Ban Specific Users
|
||||
/// </summary>
|
||||
/// <param name="model">an instance of <see>XUserNameIdRequest</see> which represents user identifier list to Ban</param>
|
||||
/// <returns>a list of banned users identifiers</returns>
|
||||
[RequireXPowered]
|
||||
[HttpPost("Ban")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledAdmin)]
|
||||
public async Task<ActionResult<IEnumerable<string>>> Ban(
|
||||
[FromBody] XUserNameIdRequest model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(model)
|
||||
.AddNotZeroChilds(model.Ids)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.Ban(
|
||||
User.Identity.Name,
|
||||
model
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UnBann Specific Users
|
||||
/// </summary>
|
||||
/// <param name="model">an instance of <see>XUserNameIdRequest</see> which represents user identifier list to Ban</param>
|
||||
/// <returns>a list of unbanned users identifiers</returns>
|
||||
[RequireXPowered]
|
||||
[HttpPost("UnBan")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledAdmin)]
|
||||
public async Task<ActionResult<IEnumerable<string>>> UnBan(
|
||||
[FromBody] XUserNameIdRequest model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(model)
|
||||
.AddNotZeroChilds(model.Ids)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.UnBan(
|
||||
User.Identity.Name,
|
||||
model
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check Specific User is Banned or not
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">specified user's identifier</param>
|
||||
/// <returns>a boolean value which represent user banned or not</returns>
|
||||
[RequireXPowered]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[HttpGet("IsBanned/{userSelectByParam?}")]
|
||||
[Authorize(Policy = XPolicies.EnabledAdmin)]
|
||||
[Authorize(Policy = XPolicies.EnabledAgent)]
|
||||
public async Task<ActionResult<bool>> IsBanned(
|
||||
[FromRoute] string userSelectByParam = null
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (userSelectByParam.IsNullOrEmpty())
|
||||
{
|
||||
userSelectByParam = User.Identity.Name;
|
||||
}
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.IsBanned(
|
||||
User.Identity.Name,
|
||||
userSelectByParam
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using IdentityModel.Client;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using xIdentityHelper;
|
||||
using xCommons.Attributes;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels.Extensions;
|
||||
using xIdentityModels.Models;
|
||||
using static IdentityServer4.IdentityServerConstants;
|
||||
using static xIdentityHelper.XApiScopeHelper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace xIds.Controllers
|
||||
{
|
||||
public partial class AccountController
|
||||
{
|
||||
//
|
||||
#region Authentication Actions ...
|
||||
/// <summary>
|
||||
/// Retrieve OAuth Discovery Document
|
||||
/// </summary>
|
||||
/// <returns>an instance of <see>DiscoveryDocumentResponse</see></returns>
|
||||
[AllowAnonymous]
|
||||
[RequireXPowered]
|
||||
[HttpGet("DiscoveryDocument")]
|
||||
public async Task<ActionResult<DiscoveryDocumentResponse>> GetDiscoveryDocument()
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.RequestDiscoveryDocument();
|
||||
|
||||
//
|
||||
// Ceck Response Result ...
|
||||
if (result.IsError)
|
||||
{
|
||||
XException.InvalidConfiguration.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request AccessToken for Specific XApiScope
|
||||
/// </summary>
|
||||
/// <param name="scope">a member of <see>XApiScope</see></param>
|
||||
/// <returns>an instance of <see>XTokenResponse</see></returns>
|
||||
[AllowAnonymous]
|
||||
[RequireXPowered]
|
||||
[HttpPost("RequestScopeAccessToken")]
|
||||
public async Task<ActionResult<XTokenResponse>> RequestScopeAccessToken(
|
||||
[FromHeader] XApiScope scope
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
var scopeName = string.Empty;
|
||||
try
|
||||
{
|
||||
scopeName = scope.GetStringValue();
|
||||
}
|
||||
catch { }
|
||||
ValidationProvider.NotEmpty(scopeName);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.RequestScopeAccessToken(scopeName);
|
||||
|
||||
//
|
||||
// Ceck Response Result ...
|
||||
if (result.IsError)
|
||||
{
|
||||
XException.InvalidConfiguration.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.CreateXTokenResponse()
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authenticate User
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Sample request:
|
||||
///
|
||||
/// {
|
||||
/// "password": "",
|
||||
/// "userSelectBy": "",
|
||||
/// }
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="model">an instance of <see>XLoginRequest</see> class which represent Authentication requirements</param>
|
||||
/// <returns>an instance of <see>XTokenResponse</see></returns>
|
||||
[AllowAnonymous]
|
||||
[RequireXPowered]
|
||||
[HttpPost("Authenticate")]
|
||||
public async Task<ActionResult<XTokenResponse>> Authenticate(
|
||||
[FromBody] XLoginRequest model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(model)
|
||||
.AddNotEmpty(
|
||||
model.UserSelectBy,
|
||||
model.Password
|
||||
)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.Authenticate(model);
|
||||
|
||||
//
|
||||
// Check Result ...
|
||||
if (result.IsError)
|
||||
{
|
||||
throw result.GetException();
|
||||
}
|
||||
|
||||
//
|
||||
// Return Result ...
|
||||
return Ok(result
|
||||
.CreateXTokenResponse()
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authenticate User
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Sample request:
|
||||
///
|
||||
/// {
|
||||
/// "language": "fa-IR"
|
||||
/// "password": "",
|
||||
/// "userSelectBy": "",
|
||||
/// "device": {
|
||||
/// "os":"Mac",
|
||||
/// "browser":"Chrome",
|
||||
/// "osVersion":"mac-os-x-15",
|
||||
/// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36",
|
||||
/// "deviceType":3,
|
||||
/// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]",
|
||||
/// "token":"96f400dd9aa5c57a8cec9d6f4775bad3"
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="model">an instance of <see>XLoginRequest</see> class which represent Authentication requirements</param>
|
||||
/// <returns>an instance of <see>XLoginResponse</see></returns>
|
||||
[AllowAnonymous]
|
||||
[RequireXPowered]
|
||||
[HttpPost("Login")]
|
||||
public async Task<ActionResult<XLoginResponse>> Login(
|
||||
[FromBody] XLoginRequest model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(
|
||||
model,
|
||||
model.Device)
|
||||
.AddNotEmpty(
|
||||
model.Language,
|
||||
model.UserSelectBy,
|
||||
model.Password
|
||||
)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.Login(model);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh Expired Tokens
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// in addition to AccessToken, you had to pass RefreshToken due to Headers
|
||||
/// </remarks>
|
||||
/// <returns>an instance of <see>XTokenResponse</see></returns>
|
||||
[AllowAnonymous]
|
||||
[RequireXPowered]
|
||||
[HttpPost("RefreshTokens")]
|
||||
public async Task<ActionResult<XTokenResponse>> RefreshTokens()
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Retrieve Toke Response ...
|
||||
var model = await RetrieveTokensAsXTokenResponse();
|
||||
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(model)
|
||||
.AddNotEmpty(
|
||||
model.AccessToken,
|
||||
model.RefreshToken)
|
||||
.ValidateGroup();
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.RefreshTokens(model);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Password Actions ...
|
||||
/// <summary>
|
||||
/// Change a User's Password ...
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// for this action you have to provide:
|
||||
/// - Lang: client device currently used locale, such as: en-US.
|
||||
/// - Password: user's current active password.
|
||||
/// - NewPassword: user's new password to change.
|
||||
/// - Device: user's client device which is an instance of XDevice.
|
||||
/// - ReturnUrl: client application Login URL.
|
||||
///
|
||||
/// Sample request:
|
||||
///
|
||||
/// {
|
||||
/// "lang": "fa-IR",
|
||||
/// "password": ""
|
||||
/// "newPassword": "",
|
||||
/// "returnUrl": "http://localhost/login",
|
||||
/// "device": {
|
||||
/// "os":"Mac",
|
||||
/// "browser":"Chrome",
|
||||
/// "osVersion":"mac-os-x-15",
|
||||
/// "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36",
|
||||
/// "deviceType":3,
|
||||
/// "identifier":"[Mac]-[mac-os-x-15]-[3]-[Chrome]-[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) x-framework-test/0.0.0 Chrome/87.0.4280.141 Electron/11.2.0 Safari/537.36]",
|
||||
/// "token":"96f400dd9aa5c57a8cec9d6f4775bad3"
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="model">an instance of <see>XActionRequest</see> class which provider requirement for action</param>
|
||||
/// <returns></returns>
|
||||
[RequireXPowered]
|
||||
[HttpPost("ChangePassword")]
|
||||
[Authorize(Policy = XPolicies.User)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
public async Task<ActionResult> ChangePassword(
|
||||
[FromBody] XActionRequest model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(
|
||||
model,
|
||||
model.Device
|
||||
)
|
||||
.AddNotEmpty(
|
||||
model.Lang,
|
||||
model.Password,
|
||||
model.NewPassword,
|
||||
model.ReturnUrl
|
||||
)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
// Get User Select By ...
|
||||
var userSelectByParam = GetUserSelectByParam(
|
||||
model,
|
||||
forceNotNull: false
|
||||
);
|
||||
if (userSelectByParam.IsNullOrEmpty())
|
||||
{
|
||||
userSelectByParam = User.Identity.Name;
|
||||
}
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
|
||||
//
|
||||
// Get Request ...
|
||||
await IdentityManager
|
||||
.ChangePassword(
|
||||
model.Lang,
|
||||
model.Device,
|
||||
userSelectByParam,
|
||||
model.Password,
|
||||
model.NewPassword,
|
||||
model.ReturnUrl
|
||||
);
|
||||
|
||||
//
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,889 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using xCommons.Attributes;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityHelper;
|
||||
using xIdentityModels.Constants;
|
||||
using xIdentityModels.Dtos;
|
||||
using xIdentityModels.Navigations;
|
||||
using xModels.Dtos;
|
||||
using static IdentityServer4.IdentityServerConstants;
|
||||
|
||||
namespace xIds.Controllers
|
||||
{
|
||||
public partial class AccountController
|
||||
{
|
||||
//
|
||||
#region Friendship Actions ...
|
||||
//
|
||||
#region Actions ...
|
||||
/// <summary>
|
||||
/// Follow a User
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns>an instance of <see>XFriendshipFollowing</see></returns>
|
||||
[RequireXPowered]
|
||||
[HttpPost("Friendship/{destUser}/Follow")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XFriendshipFollowing>> Follow(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.Follow(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancel Following
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
[HttpPost("Friendship/{destUser}/Cancel")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<bool>> Cancel(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.Cancel(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unfollow a Follower
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("Friendship/{destUser}/UnFollowFollower")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult> UnFollowFollower(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
await IdentityManager
|
||||
.UnFollowFollower(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unfollow Following
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns></returns>
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
[HttpPost("Friendship/{destUser}/UnFollowFollowing")]
|
||||
public async Task<ActionResult> UnFollowFollowing(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
await IdentityManager
|
||||
.UnFollowFollowing(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Block a Follower
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns>an instance of <see>XFriendshipFollowing</see></returns>
|
||||
[HttpPost("Friendship/{destUser}/Block")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XFriendshipFollowing>> Block(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.Block(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
|
||||
//
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unblock a Blocked User
|
||||
/// </summary>
|
||||
/// <param name="destUser">an instance of <see>XFriendshipFollowing</see></param>
|
||||
/// <returns>an instance of <see>XFriendshipFollowing</see></returns>
|
||||
[HttpPost("Friendship/{destUser}/UnBlock")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XFriendshipFollowing>> UnBlock(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.UnBlock(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Request Handlers ...
|
||||
/// <summary>
|
||||
/// Accept a Following Request
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns>an instance of <see>XFriendshipFollower</see></returns>
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
[HttpPost("Friendship/{destUser}/AcceptRequest")]
|
||||
public async Task<ActionResult<XFriendshipFollower>> AcceptRequest(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.AcceptRequest(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reject a Following Request
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns>an instance of <see>XFriendshipFollower</see></returns>
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
[HttpPost("Friendship/{destUser}/RejectRequest")]
|
||||
public async Task<ActionResult<XFriendshipFollower>> RejectRequest(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.RejectRequest(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Getters ...
|
||||
/// <summary>
|
||||
/// Check a User IsFollower of Requested User
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
[HttpGet("Friendship/{destUser}/IsFollower")]
|
||||
public async Task<ActionResult<bool>> IsFollower(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.IsFollower(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Follower State of a User
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns>an instance of <see>XFriendshipState</see></returns>
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
[HttpGet("Friendship/{destUser}/FollowerState")]
|
||||
public async Task<ActionResult<XFriendshipState>> FollowerState(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.GetFollowerState(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Specific Follower
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns>an instance of <see>XFriendshipFollower</see></returns>
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
[HttpGet("Friendship/{destUser}/Follower")]
|
||||
public async Task<ActionResult<XFriendshipFollower>> Follower(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.GetFollower(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Followers List Of Current User
|
||||
/// </summary>
|
||||
/// <returns>a collection of <see>XFriendshipFollower</see></returns>
|
||||
[HttpGet("Friendship/Followers")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<IEnumerable<XFriendshipFollower>>> Followers()
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.GetFollowers(User.Identity.Name);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
|
||||
//
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get All Followers List Includes Blocked, Requested and etc
|
||||
/// of Current User
|
||||
/// </summary>
|
||||
/// <returns>a collection of <see>XFriendshipFollower</see></returns>
|
||||
[HttpGet("Friendship/AllFollowers")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<IEnumerable<XFriendshipFollower>>> AllFollowers()
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.GetAllFollowers(User.Identity.Name);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get All Followers List Includes Blocked, Requested and etc
|
||||
/// of Current User based On Query Model ...
|
||||
/// </summary>
|
||||
/// <returns>a Query Result of <see>XFriendDto</see></returns>
|
||||
[HttpGet("Friendship/QueryFollowers")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XQueryResult<XFriendDto>>> QueryFollowers(
|
||||
[FromQuery] XQuery query,
|
||||
[FromQuery] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Normalizing Dest User ...
|
||||
var userInfo = await GetUserInfo();
|
||||
bool isAdmin = userInfo.Roles.Contains(XUserRoles.ADMIN);
|
||||
if (destUser.IsNullOrEmpty())
|
||||
{
|
||||
destUser = userInfo.UserName;
|
||||
}
|
||||
bool isDestUserValid = isAdmin || destUser == userInfo.UserId || destUser == userInfo.Email || destUser == userInfo.PhoneNumber || destUser == userInfo.UserName;
|
||||
if (!isDestUserValid)
|
||||
{
|
||||
XException.NotAllowed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.QueryFollowers(
|
||||
query: query,
|
||||
userSelectByParam: destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a User is in Followings of Current User
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
[HttpGet("Friendship/{destUser}/IsFollowing")]
|
||||
public async Task<ActionResult<bool>> IsFollowing(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.IsFollowing(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Following State Relation between Specific User
|
||||
/// and Current User
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns>an instance of <see>XFriendshipState</see></returns>
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
[HttpGet("Friendship/{destUser}/FollowingState")]
|
||||
public async Task<ActionResult<XFriendshipState>> FollowingState(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.GetFollowingState(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Specific Following Model
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns>an instance of <see>XFriendshipFollowing</see></returns>
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
[HttpGet("Friendship/{destUser}/Following")]
|
||||
public async Task<ActionResult<XFriendshipFollowing>> Following(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(destUser);
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.GetFollowing(
|
||||
User.Identity.Name,
|
||||
destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Followings of Current User
|
||||
/// </summary>
|
||||
/// <returns>a collection of <see>XFriendshipFollowing</see></returns>
|
||||
[HttpGet("Friendship/Followings")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<IEnumerable<XFriendshipFollowing>>> Followings()
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.GetFollowings(User.Identity.Name);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get All Following List Includes Blocked, Requested and etc
|
||||
/// of Current User
|
||||
/// </summary>
|
||||
/// <returns>a collection of <see>XFriendshipFollowing</see></returns>
|
||||
[HttpGet("Friendship/AllFollowings")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<IEnumerable<XFriendshipFollowing>>> AllFollowings()
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.GetAllFollowings(User.Identity.Name);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get All Following List Includes Blocked, Requested and etc
|
||||
/// of Current User based On Query Model ...
|
||||
/// </summary>
|
||||
/// <returns>a Query Result of <see>XFriendDto</see></returns>
|
||||
[HttpGet("Friendship/QueryFollowings")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XQueryResult<XFriendDto>>> QueryFollowings(
|
||||
[FromQuery] XQuery query,
|
||||
[FromQuery] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Normalizing Dest User ...
|
||||
var userInfo = await GetUserInfo();
|
||||
bool isAdmin = userInfo.Roles.Contains(XUserRoles.ADMIN);
|
||||
if (destUser.IsNullOrEmpty())
|
||||
{
|
||||
destUser = userInfo.UserName;
|
||||
}
|
||||
bool isDestUserValid = isAdmin || destUser == userInfo.UserId || destUser == userInfo.Email || destUser == userInfo.PhoneNumber || destUser == userInfo.UserName;
|
||||
if (!isDestUserValid)
|
||||
{
|
||||
XException.NotAllowed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.QueryFollowings(
|
||||
query: query,
|
||||
userSelectByParam: destUser
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Others ...
|
||||
/// <summary>
|
||||
/// Return Following UserName's List of Current User
|
||||
/// </summary>
|
||||
/// <returns>a collection of UserNames</returns>
|
||||
[HttpGet("Friendship/FollowingsList")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<IEnumerable<string>>> FollowingsList()
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.GetFollowingList(User.Identity.Name);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return Followers UserName's List of Current User
|
||||
/// </summary>
|
||||
/// <returns>a collection of UserNames</returns>
|
||||
[HttpGet("Friendship/FollowersList")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<IEnumerable<string>>> FollowersList()
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.GetFollowersList(User.Identity.Name);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Friendship Info Model between Specific User and Current User
|
||||
/// </summary>
|
||||
/// <param name="destUser">a user identifier which represent destination user</param>
|
||||
/// <returns>an instance of <see>XFriendshipInfoDto</see></returns>
|
||||
[HttpGet("Friendship/{destUser}/FriendshipInfo")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XFriendshipInfoDto>> FriendshipInfo(
|
||||
[FromRoute] string destUser
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.GetFriendshipInfo(User.Identity.Name, destUser);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using xCommons.Attributes;
|
||||
using xCommons.Constants;
|
||||
using xIdentityModels.Dtos;
|
||||
|
||||
namespace xIds.Controllers
|
||||
{
|
||||
public partial class AccountController
|
||||
{
|
||||
//
|
||||
// Implememnt all Open Actions here ...
|
||||
|
||||
//
|
||||
#region Open Actions ...
|
||||
[AllowAnonymous]
|
||||
[RequireXPowered]
|
||||
[HttpGet("Open")]
|
||||
public async Task<ActionResult<string>> Get(
|
||||
[FromHeader] string token,
|
||||
[FromQuery] string request
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotEmpty(token)
|
||||
.AddNotEmpty(request)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
// Prepare Inner Dto Model ...
|
||||
var dto = new XOpenActionInnerDto
|
||||
{
|
||||
Token = token,
|
||||
Payload = request
|
||||
};
|
||||
|
||||
//
|
||||
// Do Action ...
|
||||
var resultDto = await IdentityManager.OpenGet(dto);
|
||||
Response.Headers.Add(XAuthentication.TOKEN, resultDto.Token);
|
||||
|
||||
//
|
||||
// Return Result
|
||||
return Ok(resultDto.Payload);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Private ...
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,511 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using xIdentityHelper;
|
||||
using xCommons.Attributes;
|
||||
using xCommons.Extensions;
|
||||
using xIdentityModels.Dtos;
|
||||
using xIdentityModels.Models;
|
||||
using xModels.Dtos;
|
||||
using static IdentityServer4.IdentityServerConstants;
|
||||
|
||||
namespace xIds.Controllers
|
||||
{
|
||||
public partial class AccountController
|
||||
{
|
||||
//
|
||||
#region Retrieve Actions ...
|
||||
/// <summary>
|
||||
/// Retrieve User Names based on UserIds
|
||||
/// </summary>
|
||||
/// <param name="ids">a comma seperated list of UserIds</param>
|
||||
/// <returns>a collection of UserNames</returns>
|
||||
[HttpGet("Profile/{ids}/GetNames")]
|
||||
[Authorize(Policy = XPolicies.User)]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<IEnumerable<string>>> GetNames(
|
||||
[FromRoute] string ids
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotEmpty(ids);
|
||||
|
||||
//
|
||||
var xIdList = ids.ParseListString<string>();
|
||||
var result = await IdentityManager.GetUserNamesAsync(
|
||||
xIdList
|
||||
);
|
||||
|
||||
//
|
||||
// Return Result
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
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> instance</returns>
|
||||
[HttpPost("Profile/GetNameIds")]
|
||||
[Authorize(Policy = XPolicies.User)]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<IEnumerable<XUserNameIdResponse>>> GetNameIds(
|
||||
[FromBody] XUserNameIdRequest model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotNull(model);
|
||||
|
||||
//
|
||||
var result = await IdentityManager.GetUserNameIdsAsync(
|
||||
model
|
||||
);
|
||||
|
||||
//
|
||||
// Return Result
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Profile Object of Specific User
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">specifies which user profile must be retrieved</param>
|
||||
/// <returns>an instance of <see>XUserProfileDto</see></returns>
|
||||
[RequireXPowered]
|
||||
[Authorize(Policy = XPolicies.User)]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[HttpGet("Profile/{userSelectByParam?}")]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XUserProfileDto>> GetProfile(
|
||||
[FromRoute] string userSelectByParam = ""
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
if (userSelectByParam.IsNullOrEmpty())
|
||||
{
|
||||
userSelectByParam = User.Identity.Name;
|
||||
}
|
||||
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.GetUserProfileAsync(
|
||||
userSelectByParam,
|
||||
User.Identity.Name
|
||||
);
|
||||
|
||||
//
|
||||
// Return Result
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query Users
|
||||
/// for specifiy users role for query user 'role: string' and 'forceRole: boolean' in header
|
||||
/// </summary>
|
||||
/// <param name="query">how to filter results based on <see>XQuery</see> structure</param>
|
||||
/// <param name="role">an string which represent user role</param>
|
||||
/// <param name="forceRole">if it's true the user must has exact role, otherwise top level users also listed</param>
|
||||
/// <returns>an instance of <see>XQueryResult</see> of <see>XUserProfileDto</see></returns>
|
||||
[RequireXPowered]
|
||||
[HttpGet("Profile/Query")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledAdmin)]
|
||||
[Authorize(Policy = XPolicies.EnabledAgent)]
|
||||
public async Task<ActionResult<XQueryResult<XUserProfileDto>>> QueryProfiles(
|
||||
[FromQuery] XQuery query, [FromHeader] string role, [FromHeader] bool forceRole = false
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var userId = User.Identity.Name;
|
||||
|
||||
//
|
||||
var result = new XQueryResult<XUserProfileDto>();
|
||||
if (role.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
result = await IdentityManager.QueryUsers(
|
||||
userId,
|
||||
query
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
result = await IdentityManager.QueryInRoleUsers(
|
||||
userId,
|
||||
role,
|
||||
query,
|
||||
forceRole
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exception = GetExceptionActionResult(ex);
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query Specified User's Profile Images
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">determine's which user profile must be retrieved</param>
|
||||
/// <param name="query">how to filter results based on <see>XQuery</see> structure</param>
|
||||
/// <returns>an instance of <see>XQueryResult</see> of <see>XProfileImage</see></returns>
|
||||
[RequireXPowered]
|
||||
[Authorize(Policy = XPolicies.User)]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
[Authorize(Policy = XPolicies.EnabledAdmin)]
|
||||
[HttpGet("Profile/Avatars/Query/{userSelectByParam?}")]
|
||||
public async Task<ActionResult<XQueryResult<XProfileImageDto>>> QueryAvatars(
|
||||
[FromQuery] XQuery query, [FromRoute] string userSelectByParam = null
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
if (userSelectByParam.IsNullOrEmpty())
|
||||
{
|
||||
userSelectByParam = User.Identity.Name;
|
||||
}
|
||||
|
||||
//
|
||||
var result = await IdentityManager.QueryAvatars(
|
||||
userSelectByParam,
|
||||
query
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exception = GetExceptionActionResult(ex);
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Update Actions ...
|
||||
/// <summary>
|
||||
/// Update User Profile based on XProfileUpdateRequest (FirstName/LastName/DateOfBirth)
|
||||
/// </summary>
|
||||
/// <param name="model">user update info, an instance of <see>XProfileUpdateRequest</see></param>
|
||||
/// <param name="userSelectByParam">determine's which user profile must be retrieved</param>
|
||||
/// <returns>an instance of <see>XUserProfileDto</see></returns>
|
||||
[RequireXPowered]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
[HttpPost("Profile/Update/{userSelectByParam?}")]
|
||||
public async Task<ActionResult<XUserProfileDto>> UpdateProfile(
|
||||
[FromBody] XProfileUpdateRequest model, [FromRoute] string userSelectByParam = null
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
if (userSelectByParam.IsNullOrEmpty())
|
||||
{
|
||||
userSelectByParam = User.Identity.Name;
|
||||
}
|
||||
|
||||
//
|
||||
var result = await IdentityManager.ProfileUpdateAsync(
|
||||
userSelectByParam,
|
||||
User.Identity.Name,
|
||||
model
|
||||
);
|
||||
|
||||
//
|
||||
// Return Result
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update a User Profile based on XProfileUpdateRequest Full
|
||||
/// </summary>
|
||||
/// <param name="model">user update info, an instance of <see>XProfileUpdateRequest</see></param>
|
||||
/// <param name="userSelectByParam">determine's which user profile must be retrieved</param>
|
||||
/// <returns>an instance of <see>XUserProfileDto</see></returns>
|
||||
[RequireXPowered]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[HttpPost("Profile/{userSelectByParam?}")]
|
||||
[Authorize(Policy = XPolicies.EnabledAdminOrAgent)]
|
||||
public async Task<ActionResult<XUserProfileDto>> FullUpdateProfile(
|
||||
[FromBody] XProfileUpdateRequest model, [FromRoute] string userSelectByParam = null
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
if (userSelectByParam.IsNullOrEmpty())
|
||||
{
|
||||
userSelectByParam = User.Identity.Name;
|
||||
}
|
||||
|
||||
//
|
||||
var result = await IdentityManager.FullProfileUpdateAsync(
|
||||
userSelectByParam,
|
||||
User.Identity.Name,
|
||||
model
|
||||
);
|
||||
|
||||
//
|
||||
// Return Result
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Avatar Actions ...
|
||||
/// <summary>
|
||||
/// Add a New Profile Image
|
||||
/// </summary>
|
||||
/// <param name="file">an specific File to upload, <see>IFormFile</see></param>
|
||||
/// <returns>an instance of <see>XUserProfileDto</see></returns>
|
||||
[RequireXPowered]
|
||||
[HttpPost("Profile/Avatar")]
|
||||
[RequestSizeLimit(966_367_641)]
|
||||
[Authorize(Policy = XPolicies.User)]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XUserProfileDto>> AddAvatar(
|
||||
[FromForm] IFormFile file
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotNull(file);
|
||||
|
||||
//
|
||||
// Get Request ...
|
||||
var result = await IdentityManager
|
||||
.AddAvatar(
|
||||
User.Identity.Name,
|
||||
file
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a New Collection of Profile Images
|
||||
/// </summary>
|
||||
/// <param name="files">a collection of Files to upload, <see>IFormFileCollection</see></param>
|
||||
/// <returns>an instance of <see>XUserProfileDto</see></returns>
|
||||
[RequireXPowered]
|
||||
[HttpPost("Profile/Avatars")]
|
||||
[RequestSizeLimit(966_367_641)]
|
||||
[Authorize(Policy = XPolicies.User)]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XUserProfileDto>> AddAvatars(
|
||||
[FromForm] IFormFileCollection files
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotZeroChilds(files);
|
||||
|
||||
//
|
||||
// Get Request ...
|
||||
var result = await IdentityManager.AddAvatars(
|
||||
User.Identity.Name,
|
||||
files
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exResult = GetExceptionActionResult(ex);
|
||||
return exResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove Profile Images
|
||||
/// </summary>
|
||||
/// <param name="ids">a comma seperated list of avatarIds to remove</param>
|
||||
/// <returns>an instance of <see>XUserProfileDto</see></returns>
|
||||
[RequireXPowered]
|
||||
[Authorize(Policy = XPolicies.User)]
|
||||
[HttpDelete("Profile/Avatars/{ids}")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XUserProfileDto>> RemoveAvatars(
|
||||
[FromRoute] string ids
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotEmpty(ids);
|
||||
var idList = ids.Split(",");
|
||||
var idCollection = new Collection<int>();
|
||||
|
||||
//
|
||||
foreach (var s in idList)
|
||||
{
|
||||
idCollection.Add(int.Parse(s));
|
||||
}
|
||||
|
||||
//
|
||||
// Get Request ...
|
||||
var result = await IdentityManager
|
||||
.RemoveAvatar(
|
||||
User.Identity.Name,
|
||||
idCollection.ToArray()
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var result = GetExceptionActionResult(ex);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// set Specified Profile Image as Avatar
|
||||
/// </summary>
|
||||
/// <param name="id">an integer which reperesent AvatarId to set as current Avatar</param>
|
||||
/// <returns>an instance of <see>XUserProfileDto</see></returns>
|
||||
[RequireXPowered]
|
||||
[HttpPost("Profile/Avatars/{id:int}/Set")]
|
||||
[Authorize(Policy = XPolicies.User)]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XUserProfileDto>> SetAvatar(
|
||||
[FromRoute] int id
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var result = await IdentityManager
|
||||
.SetAvatar(
|
||||
User.Identity.Name,
|
||||
id
|
||||
);
|
||||
|
||||
//
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exception = GetExceptionActionResult(ex);
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using xCommons.Attributes;
|
||||
using xCommons.Extensions;
|
||||
using xIdentityHelper;
|
||||
using xModels.Dtos;
|
||||
using static IdentityServer4.IdentityServerConstants;
|
||||
|
||||
namespace xIds.Controllers
|
||||
{
|
||||
public partial class AccountController
|
||||
{
|
||||
/// <summary>
|
||||
/// Query Users
|
||||
/// for specifiy users role for query user 'role: string' and 'forceRole: boolean' in header
|
||||
/// </summary>
|
||||
/// <param name="query">how to filter results based on <see>XQuery</see> structure</param>
|
||||
/// <param name="role">an string which represent user role</param>
|
||||
/// <param name="forceRole">if it's true the user must has exact role, otherwise top level users also listed</param>
|
||||
/// <returns>an instance of <see>XQueryResult</see> of <see>XUserProfileDto</see></returns>
|
||||
[RequireXPowered]
|
||||
[HttpGet("Users/Query")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XQueryResult<string>>> QueryUsers(
|
||||
[FromQuery] XQuery query,
|
||||
[FromHeader] string role,
|
||||
[FromHeader] bool forceRole = false
|
||||
)
|
||||
{
|
||||
//
|
||||
// Do Actions ...
|
||||
try
|
||||
{
|
||||
//
|
||||
// Retrieve User Info ...
|
||||
var userInfo = await GetUserInfo();
|
||||
|
||||
//
|
||||
// Retrieve Result Based on Provided Query ...
|
||||
var result = await IdentityManager.QueryUsers(
|
||||
role: role,
|
||||
query: query,
|
||||
forceRole: forceRole,
|
||||
requestedUserSelectByParam: userInfo.UserId
|
||||
);
|
||||
|
||||
//
|
||||
// Return result ...
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exception = GetExceptionActionResult(ex);
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using xCommons.Attributes;
|
||||
using xCommons.Extensions;
|
||||
using xIdentityHelper;
|
||||
using xIdentityModels.Dtos;
|
||||
using xModels.Dtos;
|
||||
using static IdentityServer4.IdentityServerConstants;
|
||||
|
||||
namespace xIds.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Actions which related to Search and Suggest Users for
|
||||
/// Friendship or Detecting ...
|
||||
/// </summary>
|
||||
public partial class AccountController
|
||||
{
|
||||
//
|
||||
#region Actions of Search ...
|
||||
/// <summary>
|
||||
/// Query Open To Search Users Profiles ...
|
||||
/// Query all Users Which their Profiles is Open To Search ...
|
||||
/// </summary>
|
||||
/// <param name="query">how to filter results based on <see>XQuery</see> structure</param>
|
||||
/// <returns>an instance of <see>XQueryResult</see> of <see>XUserProfileDto</see></returns>
|
||||
[RequireXPowered]
|
||||
[HttpGet("OpenToSearch/Query")]
|
||||
[Authorize(Policy = LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public async Task<ActionResult<XQueryResult<XUserProfileDto>>> QueryOpenToSearchProfiles(
|
||||
[FromQuery] XQuery query)
|
||||
{
|
||||
//
|
||||
// Do Action ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var userId = User.Identity.Name;
|
||||
|
||||
//
|
||||
var result = await IdentityManager.QueryOpenToSearchUsers(
|
||||
userId,
|
||||
query
|
||||
);
|
||||
|
||||
return Ok(result
|
||||
.ToDynamicObject());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//
|
||||
var exception = GetExceptionActionResult(ex);
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using xIdentityHelper;
|
||||
using xCommons.Attributes;
|
||||
using static IdentityServer4.IdentityServerConstants;
|
||||
|
||||
namespace xIds.Controllers
|
||||
{
|
||||
public partial class AccountController
|
||||
{
|
||||
|
||||
//
|
||||
#region Test Actions ...
|
||||
/// <summary>
|
||||
/// API Read Scope
|
||||
/// </summary>
|
||||
/// <returns>string message</returns>
|
||||
[RequireXPowered]
|
||||
[Authorize(LocalApi.PolicyName)]
|
||||
[HttpGet("Test/PassReadAccess")]
|
||||
[Authorize(Policy = XPolicies.ReadAccess)]
|
||||
public ActionResult<string> PassReadAccess()
|
||||
{
|
||||
return Ok("Read Access Passed ...");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API Write Scope
|
||||
/// </summary>
|
||||
/// <returns>string message</returns>
|
||||
[RequireXPowered]
|
||||
[Authorize(LocalApi.PolicyName)]
|
||||
[HttpGet("Test/PassWriteAccess")]
|
||||
[Authorize(Policy = XPolicies.WriteAccess)]
|
||||
public ActionResult<string> PassWriteAccess()
|
||||
{
|
||||
return Ok("Write Access Passed ...");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API Admin Scope
|
||||
/// </summary>
|
||||
/// <returns>string message</returns>
|
||||
[RequireXPowered]
|
||||
[Authorize(LocalApi.PolicyName)]
|
||||
[HttpGet("Test/PassAdminAccess")]
|
||||
[Authorize(Policy = XPolicies.AdminAccess)]
|
||||
public ActionResult<string> PassAdminAccess()
|
||||
{
|
||||
return Ok("Admin Access Passed ...");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API Manage Scop
|
||||
/// </summary>
|
||||
/// <returns>string message</returns>
|
||||
[RequireXPowered]
|
||||
[Authorize(LocalApi.PolicyName)]
|
||||
[HttpGet("Test/PassManageAccess")]
|
||||
[Authorize(Policy = XPolicies.ManageAccess)]
|
||||
public ActionResult<string> PassManageAccess()
|
||||
{
|
||||
return Ok("Manage Access Passed ...");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// a simple Action which returns a List of Authenticated User Claims
|
||||
/// </summary>
|
||||
/// <returns>string message which represent current user's claims</returns>
|
||||
[RequireXPowered]
|
||||
[HttpGet("Test/HiClaims")]
|
||||
[Authorize(LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.User)]
|
||||
public ActionResult<string> HiClaims()
|
||||
{
|
||||
//
|
||||
var result = new
|
||||
{
|
||||
name = User.Identity.Name,
|
||||
claims = User.Claims.Select(c => new
|
||||
{
|
||||
c.Type,
|
||||
c.Value
|
||||
})
|
||||
};
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// a simple Hello User for Checking Authentication and Policy
|
||||
/// </summary>
|
||||
/// <returns>string message which contains authenticated user name</returns>
|
||||
[RequireXPowered]
|
||||
[HttpGet("Test/HiUser")]
|
||||
[Authorize(LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.User)]
|
||||
public ActionResult<string> HiUser()
|
||||
{
|
||||
//
|
||||
var result = $"Hi User: {User.Identity.Name} ...";
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// a simple Hello User for Checking Authentication and Policy
|
||||
/// </summary>
|
||||
/// <returns>string message which contains authenticated user name</returns>
|
||||
[RequireXPowered]
|
||||
[HttpGet("Test/HiEnabledUser")]
|
||||
[Authorize(LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledUser)]
|
||||
public ActionResult<string> HiEnabledUser()
|
||||
{
|
||||
//
|
||||
var result = $"Hi User: {User.Identity.Name} is Enabled ...";
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// a simple Hello User for Checking Authentication and Policy
|
||||
/// </summary>
|
||||
/// <returns>string message which contains authenticated user name</returns>
|
||||
[RequireXPowered]
|
||||
[HttpGet("Test/HiAdmin")]
|
||||
[Authorize(LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.Admin)]
|
||||
public ActionResult<string> HiAdmin()
|
||||
{
|
||||
//
|
||||
var result = $"Hi Admin: {User.Identity.Name} ...";
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// a simple Hello User for Checking Authentication and Policy
|
||||
/// </summary>
|
||||
/// <returns>string message which contains authenticated user name</returns>
|
||||
[RequireXPowered]
|
||||
[HttpGet("Test/HiEnabledAdmin")]
|
||||
[Authorize(LocalApi.PolicyName)]
|
||||
[Authorize(Policy = XPolicies.EnabledAdmin)]
|
||||
public ActionResult<string> HiEnabledAdmin()
|
||||
{
|
||||
//
|
||||
var result = $"Hi Admin: {User.Identity.Name} is Enabled ...";
|
||||
|
||||
//
|
||||
return Ok(result);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Configurations;
|
||||
using xCommons.Providers;
|
||||
using xIds.Controllers.Base;
|
||||
using xIds.Interfaces;
|
||||
|
||||
namespace xIds.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Provide all available tools for manipulating users and accounts
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
public partial class AccountController : XIBaseController
|
||||
{
|
||||
|
||||
public AccountController(
|
||||
IXIdentityManager identityManager,
|
||||
ILogger<AccountController> logger,
|
||||
XAppConfiguration appConfiguration,
|
||||
XValidationProvider validationProvider
|
||||
) : base(
|
||||
logger,
|
||||
appConfiguration,
|
||||
identityManager,
|
||||
validationProvider
|
||||
)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Configurations;
|
||||
using xCommons.Constants;
|
||||
using xCommons.Controllers;
|
||||
using xCommons.Extensions;
|
||||
using xCommons.Providers;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels.Constants;
|
||||
using xIdentityModels.Models;
|
||||
using xIds.Interfaces;
|
||||
|
||||
namespace xIds.Controllers.Base
|
||||
{
|
||||
public abstract class XIBaseController : XBaseController
|
||||
{
|
||||
public IXIdentityManager IdentityManager { get; }
|
||||
|
||||
protected XIBaseController(
|
||||
ILogger logger,
|
||||
XAppConfiguration appConfiguration,
|
||||
IXIdentityManager identityManager,
|
||||
XValidationProvider validationProvider
|
||||
) : base(
|
||||
logger,
|
||||
appConfiguration,
|
||||
validationProvider
|
||||
)
|
||||
{
|
||||
IdentityManager = identityManager;
|
||||
}
|
||||
|
||||
//
|
||||
#region User Handlers NonActions ...
|
||||
/// <summary>
|
||||
/// Retrieve User Identifier Base on XActionRequest
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="forceNotNull"></param>
|
||||
/// <param name="excludes"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public string GetUserSelectByParam(
|
||||
XActionRequest model,
|
||||
bool forceNotNull = true,
|
||||
ICollection<XUserSelectBy> excludes = null)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotNull(model);
|
||||
|
||||
//
|
||||
var result = IdentityManager.GetUserSelectByParam(
|
||||
model,
|
||||
forceNotNull,
|
||||
excludes);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Access Token
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<string> GetAccessToken()
|
||||
{
|
||||
//
|
||||
var accessToken = Request.Headers[XAuthorization.Header].ToString();
|
||||
if (accessToken.IsNullOrEmpty())
|
||||
{
|
||||
accessToken = await HttpContext.GetTokenAsync(XAuthorization.AccessToken);
|
||||
}
|
||||
|
||||
//
|
||||
if (accessToken
|
||||
.ToNormalString()
|
||||
.Contains(XAuthorization.TokenIdentifier.ToNormalString()))
|
||||
{
|
||||
accessToken = accessToken.Remove(0, XAuthorization.TokenIdentifier.Length);
|
||||
}
|
||||
|
||||
//
|
||||
Logger.LogInformation($"Token: {accessToken}");
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Refresh Token
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<string> GetRefreshToken()
|
||||
{
|
||||
//
|
||||
var refreshToken = Request.Headers[XAuthorization.RefreshToken].ToString();
|
||||
if (refreshToken.IsNullOrEmpty())
|
||||
{
|
||||
refreshToken = await HttpContext.GetTokenAsync(XAuthorization.RefreshToken);
|
||||
}
|
||||
|
||||
//
|
||||
Logger.LogInformation($"Refresh Token: {refreshToken}");
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Access Token Expiration Date
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<long> GetTokenExpiresAt()
|
||||
{
|
||||
//
|
||||
var expiresAtStr = Request.Headers[XAuthorization.ExpiresAt].ToString();
|
||||
if (expiresAtStr.IsNullOrEmpty())
|
||||
{
|
||||
expiresAtStr = await HttpContext.GetTokenAsync(XAuthorization.ExpiresAt);
|
||||
}
|
||||
|
||||
//
|
||||
var expiresAt = expiresAtStr.ConvertTo<long>();
|
||||
|
||||
//
|
||||
Logger.LogInformation($"Token ExpiresAt: {expiresAtStr}");
|
||||
return expiresAt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve All Required Tokens
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<XLoginResponse> RetrieveTokensAsXLoginResponse()
|
||||
{
|
||||
//
|
||||
var accessToken = await GetAccessToken();
|
||||
var refreshToken = await GetRefreshToken();
|
||||
var expiresAt = await GetTokenExpiresAt();
|
||||
|
||||
//
|
||||
return new XLoginResponse
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
RefreshToken = refreshToken,
|
||||
ExpiresAt = expiresAt
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve All Required Tokens
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<XTokenResponse> RetrieveTokensAsXTokenResponse()
|
||||
{
|
||||
//
|
||||
var accessToken = await GetAccessToken();
|
||||
var refreshToken = await GetRefreshToken();
|
||||
var expiresAt = await GetTokenExpiresAt();
|
||||
|
||||
//
|
||||
return new XTokenResponse
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
RefreshToken = refreshToken,
|
||||
ExpiresAt = expiresAt
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrive UserInfo
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<XUserClaimsInfoDto> GetUserInfo()
|
||||
{
|
||||
//
|
||||
var claims = User.Claims ?? null;
|
||||
if (!claims.HasChild())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var xTokens = await RetrieveTokensAsXTokenResponse();
|
||||
var result = new XUserClaimsInfoDto(
|
||||
xTokens.AccessToken,
|
||||
xTokens.RefreshToken,
|
||||
xTokens.ExpiresAt,
|
||||
User.Claims
|
||||
);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate User Authenticated and Retrieve User Info
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<XUserClaimsInfoDto> ValidateAndGetUserInfo()
|
||||
{
|
||||
//
|
||||
if (!User.Identity.IsAuthenticated)
|
||||
{
|
||||
XException.NotAuthorized.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var result = await GetUserInfo();
|
||||
if (result.IsNull())
|
||||
{
|
||||
XException.NotAuthorized.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region NonActions ...
|
||||
/// <summary>
|
||||
/// Convert an Exception to Propper Error Result
|
||||
/// </summary>
|
||||
/// <param name="ex"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public new ActionResult GetExceptionActionResult(Exception ex)
|
||||
{
|
||||
//
|
||||
var exception = GetExceptionResult(ex);
|
||||
var error = ex.Message.ToXError();
|
||||
|
||||
//
|
||||
Logger.LogError($"exception: {exception}, error: {error}");
|
||||
|
||||
//
|
||||
try
|
||||
{
|
||||
var xError = exception.Message.ToXError();
|
||||
var xException = (XException)xError.Id;
|
||||
|
||||
//
|
||||
switch (xException)
|
||||
{
|
||||
//
|
||||
case XException.NotFound:
|
||||
return NotFound(error);
|
||||
|
||||
//
|
||||
case XException.NotAuthorized:
|
||||
return Unauthorized(error);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
//
|
||||
return BadRequest(error);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Configurations;
|
||||
using xCommons.Controllers;
|
||||
using xCommons.Providers;
|
||||
|
||||
namespace xIds.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Startup and Running Controller
|
||||
/// </summary>
|
||||
[Route("")]
|
||||
[AllowAnonymous]
|
||||
public class StartupController : XBaseController
|
||||
{
|
||||
public StartupController(
|
||||
ILogger<StartupController> logger,
|
||||
XAppConfiguration appConfiguration,
|
||||
XValidationProvider validationProvider
|
||||
) : base(
|
||||
logger,
|
||||
appConfiguration,
|
||||
validationProvider
|
||||
)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Show Configured Welcome Message
|
||||
/// </summary>
|
||||
/// <returns>an string message</returns>
|
||||
[HttpGet("")]
|
||||
[AllowAnonymous]
|
||||
public virtual ActionResult<string> Index()
|
||||
{
|
||||
//
|
||||
var controllerName = GetControllerName();
|
||||
var message = $"{AppConfiguration.WelcomeMessage}";
|
||||
|
||||
//
|
||||
return Ok(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,420 @@
|
||||
using System.Collections.Generic;
|
||||
using IdentityServer4;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Authorization;
|
||||
using xCommons.Constants;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityHelper;
|
||||
using xIdentityModels;
|
||||
using xIdentityModels.Configurations;
|
||||
using xIds.Configurations;
|
||||
using xIds.Constants;
|
||||
using xIds.DbContext;
|
||||
using xIds.Extensions;
|
||||
using xIds.Helpers;
|
||||
using xIds.Interfaces;
|
||||
using xIds.Providers;
|
||||
using xIds.Validators;
|
||||
using xMessageService.DI;
|
||||
using xMessageService.Interfaces;
|
||||
using xStorageService.DI;
|
||||
using xStorageService.Interfaces;
|
||||
|
||||
namespace xIds.DI
|
||||
{
|
||||
public static class XDIHelperExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Register Application DataProvider
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public static void AddXDataProvider(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration
|
||||
)
|
||||
{
|
||||
//
|
||||
// Retrieve DbInfo ...
|
||||
var dbInfo = configuration.GetXDbInfo();
|
||||
var identityDbConnectionString = configuration.GetConnectionString(ConnectionStringNames.IDENTITY_CONNECTION_NAME);
|
||||
|
||||
//
|
||||
// Register Db Context for EF ...
|
||||
services.AddDbContext<XIdentityDbContext>(builder =>
|
||||
{
|
||||
//
|
||||
builder.PrepareXDbContextOptionsBuilder(
|
||||
dbInfo,
|
||||
identityDbConnectionString
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract Connection String From IConfiguration
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="connectionName"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetXConnectionString(
|
||||
this IConfiguration config,
|
||||
string connectionName = null
|
||||
)
|
||||
{
|
||||
//
|
||||
if (connectionName.IsNullOrEmpty())
|
||||
{
|
||||
connectionName = XDbProviderConfigurations.DEFAULT_CONNECTION_NAME;
|
||||
}
|
||||
|
||||
//
|
||||
return config.GetConnectionString(connectionName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrive XDataService Configurations
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="connectionName"></param>
|
||||
/// <returns></returns>
|
||||
public static XDataServiceConfiguration GetXDataServiceConfiguration(
|
||||
this IConfiguration source,
|
||||
string connectionName = null
|
||||
)
|
||||
{
|
||||
//
|
||||
var xDataServiceConfigSection = source
|
||||
.GetSection(Constants.ConfigurationNodeNames.DATA_SERVICE_NODE_NAME);
|
||||
var result = xDataServiceConfigSection.Get<XDataServiceConfiguration>();
|
||||
if (result.IsNull())
|
||||
{
|
||||
result = new XDataServiceConfiguration();
|
||||
}
|
||||
|
||||
//
|
||||
result.Provider = source.GetXDbProviderType();
|
||||
result.ConnectionString = source.GetXConnectionString(connectionName);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register XDataService Configuration
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <param name="connectionName"></param>
|
||||
public static void AddXDataServiceConfiguration(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration,
|
||||
string connectionName = null
|
||||
)
|
||||
{
|
||||
//
|
||||
var dataServiceConfiguration = configuration
|
||||
.GetXDataServiceConfiguration(connectionName);
|
||||
|
||||
//
|
||||
services.AddSingleton<XDataServiceConfiguration>(dataServiceConfiguration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register All Requirements For XIdentityServer Usage
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public static void AddXIdentityServerRequirements(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration
|
||||
)
|
||||
{
|
||||
//
|
||||
services.AddXDataProvider(configuration);
|
||||
|
||||
//
|
||||
// Register XIdentityMessageProvider ...
|
||||
services.AddXIdentityMessageProvider();
|
||||
|
||||
//
|
||||
// Register IdentityManager Service ...
|
||||
var xIdentityManager = services.GetRegisteredService<IXIdentityManager>();
|
||||
if (xIdentityManager.IsNull())
|
||||
{
|
||||
services.AddXIdentityManager();
|
||||
}
|
||||
|
||||
//
|
||||
// Check XMessage Service Registered or not and Register it if not ...
|
||||
var xMessageProvider = services.GetRegisteredService<IXMessageProvider>();
|
||||
if (xMessageProvider.IsNull())
|
||||
{
|
||||
services.AddXMessageService(configuration);
|
||||
}
|
||||
|
||||
//
|
||||
// Check Storage Service Registered or not and Register it if not ...
|
||||
var xStorageProvider = services.GetRegisteredService<IXStorageProvider>();
|
||||
if (xStorageProvider.IsNull())
|
||||
{
|
||||
services.AddXStorageService(configuration);
|
||||
}
|
||||
|
||||
//
|
||||
// Register XIdentityConfiguration ...
|
||||
var xIdentityConfiguration = configuration.GetXIdentityConfiguration();
|
||||
services.AddSingleton<XIdentityConfiguration>(xIdentityConfiguration);
|
||||
|
||||
//
|
||||
// Register XIdentityHelper ...
|
||||
services.AddSingleton<IXIdentityHelper, XIdentityHelper>();
|
||||
var xIdentityHelper = services.GetRegisteredService<IXIdentityHelper>();
|
||||
|
||||
//
|
||||
// Register Asp.net Identity ...
|
||||
services.AddXIdentity();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add IdentityServer with Support of Ef
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public static void AddEfSupportXIdentityServer(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration
|
||||
)
|
||||
{
|
||||
//
|
||||
// Register All Requirements ...
|
||||
services.AddXIdentityServerRequirements(configuration);
|
||||
|
||||
//
|
||||
// add DbSeeder Config ...
|
||||
services.AddXDebSeederDescriptor(configuration);
|
||||
|
||||
//
|
||||
// Retrieve Certificate ...
|
||||
var identityServerSigningCertificate = configuration.GetCertificate(CertificatesConfigurations.CertificateNames.IdentityServerSigning);
|
||||
|
||||
//
|
||||
// Retrieve DbInfo ...
|
||||
var dbInfo = configuration.GetXDbInfo();
|
||||
|
||||
//
|
||||
// Retrieve Connection String Names ...
|
||||
var configDbConnectionString = configuration.GetConnectionString(ConnectionStringNames.CONFIGURATION_CONNECTION_NAME);
|
||||
var persistedGrantDbConnectionString = configuration.GetConnectionString(ConnectionStringNames.PRESISTED_GRANTS_CONNECTION_NAME);
|
||||
|
||||
//
|
||||
// Register IdentityServer ...
|
||||
services.AddIdentityServer(options =>
|
||||
{
|
||||
//
|
||||
options.Discovery.CustomEntries.Add("account_api", "~/account");
|
||||
|
||||
//
|
||||
// options.Events.RaiseErrorEvents = true;
|
||||
// options.Events.RaiseFailureEvents = true;
|
||||
// options.Events.RaiseSuccessEvents = true;
|
||||
// options.Events.RaiseInformationEvents = true;
|
||||
})
|
||||
.LoadSigningCredentialFrom(identityServerSigningCertificate)
|
||||
.AddXDbProvider(configuration)
|
||||
.AddAspNetIdentity<XUser>()
|
||||
.AddProfileService<XIdentityProfileService>()
|
||||
.AddResourceOwnerValidator<XResourceOwnerPasswordValidator>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// force app to use IdentityServer
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="logger"></param>
|
||||
public static void UseXIdentityServer(
|
||||
this IApplicationBuilder app,
|
||||
ILogger logger
|
||||
)
|
||||
{
|
||||
//
|
||||
// Update XIdentityServer Configurations before Use Identity Server ...
|
||||
app.SeedData(logger)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
|
||||
//
|
||||
// Use Identity Server ...
|
||||
app.UseIdentityServer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register Asp.net Identity as User Store
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public static void AddXIdentity(this IServiceCollection services)
|
||||
{
|
||||
//
|
||||
var xIdentityConfiguration = services.GetRegisteredService<XIdentityConfiguration>();
|
||||
if (xIdentityConfiguration.IsNull())
|
||||
{
|
||||
XException.InvalidConfiguration.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var xIdentityHelper = services.GetRegisteredService<IXIdentityHelper>();
|
||||
if (xIdentityHelper.IsNull())
|
||||
{
|
||||
XException.InvalidConfiguration.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Add Identity for User Persists ...
|
||||
services.AddIdentity<XUser, IdentityRole>(options =>
|
||||
{
|
||||
//
|
||||
var mLockoutSpan = xIdentityHelper.GetLockoutTimeSpan();
|
||||
|
||||
//
|
||||
// Lockout Setting ...
|
||||
options.Lockout.DefaultLockoutTimeSpan = mLockoutSpan;
|
||||
options.Lockout.MaxFailedAccessAttempts = xIdentityConfiguration.Policy.Lockout.MaxFailedAccessAttempts;
|
||||
options.Lockout.AllowedForNewUsers = xIdentityConfiguration.Policy.Lockout.AllowedForNewUsers;
|
||||
|
||||
//
|
||||
// Password settings ...
|
||||
options.Password.RequireDigit = xIdentityConfiguration.Policy.Password.RequireDigit;
|
||||
options.Password.RequireLowercase = xIdentityConfiguration.Policy.Password.RequireLowercase;
|
||||
options.Password.RequireNonAlphanumeric = xIdentityConfiguration.Policy.Password.RequireNonAlphanumeric;
|
||||
options.Password.RequireUppercase = xIdentityConfiguration.Policy.Password.RequireUppercase;
|
||||
options.Password.RequiredLength = xIdentityConfiguration.Policy.Password.RequiredLength;
|
||||
options.Password.RequiredUniqueChars = xIdentityConfiguration.Policy.Password.RequiredUniqueChars;
|
||||
|
||||
//
|
||||
// SignIn settings ...
|
||||
options.SignIn.RequireConfirmedEmail = xIdentityConfiguration.Policy.SignIn.RequireConfirmedEmail;
|
||||
options.SignIn.RequireConfirmedPhoneNumber = xIdentityConfiguration.Policy.SignIn.RequireConfirmedPhoneNumber;
|
||||
|
||||
//
|
||||
// User settings ...
|
||||
options.User.AllowedUserNameCharacters = xIdentityConfiguration.Policy.User.AllowedUserNameCharacters;
|
||||
options.User.RequireUniqueEmail = xIdentityConfiguration.Policy.User.RequireUniqueEmail;
|
||||
})
|
||||
.AddEntityFrameworkStores<XIdentityDbContext>()
|
||||
.AddDefaultTokenProviders();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register IdentityServer Based Authentication
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public static void AddXIdentityServerAuthentication(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration
|
||||
)
|
||||
{
|
||||
//
|
||||
services.AddXIdentityResourceConfiguration(configuration);
|
||||
services.AddAuthentication()
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
//
|
||||
options.SaveToken = true;
|
||||
options.RequireHttpsMetadata = false;
|
||||
|
||||
//
|
||||
options.ForwardDefault = XAuthentication.IDENTITY_SERVER_LOCAL_API;
|
||||
})
|
||||
.AddLocalApi();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register Authorization Policies
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="policies"></param>
|
||||
public static void AddXAuthorization(
|
||||
this IServiceCollection services,
|
||||
IDictionary<string, AuthorizationPolicy> policies = null
|
||||
)
|
||||
{
|
||||
//
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
//
|
||||
if (!policies.IsNull())
|
||||
{
|
||||
//
|
||||
// Fill Policies ...
|
||||
using (var policiesEnumerator = policies.GetEnumerator())
|
||||
{
|
||||
while (policiesEnumerator.MoveNext())
|
||||
{
|
||||
var policyDescriptor = policiesEnumerator.Current;
|
||||
options.AddPolicy(policyDescriptor.Key, policyDescriptor.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
var xPolicies = XAuthorizationHelper.GetXAuthorizationPolicies();
|
||||
if (!xPolicies.IsNull())
|
||||
{
|
||||
//
|
||||
// Fill Policies ...
|
||||
using (var policiesEnumerator = xPolicies.GetEnumerator())
|
||||
{
|
||||
while (policiesEnumerator.MoveNext())
|
||||
{
|
||||
var policyDescriptor = policiesEnumerator.Current;
|
||||
options.AddPolicy(policyDescriptor.Key, policyDescriptor.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Add Local APi Policy ...
|
||||
options.AddPolicy(IdentityServerConstants.LocalApi.PolicyName, policy =>
|
||||
{
|
||||
//
|
||||
policy.AddAuthenticationSchemes(IdentityServerConstants.LocalApi.AuthenticationScheme);
|
||||
policy.RequireAuthenticatedUser();
|
||||
});
|
||||
});
|
||||
|
||||
//
|
||||
services.AddSingleton<IAuthorizationHandler, RequiredRolesHandler>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use Forward Headers Options for resolving behind a proxy issues ...
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
public static void UseXForwardOptions(this IApplicationBuilder source)
|
||||
{
|
||||
//
|
||||
var forwardOptions = new ForwardedHeadersOptions
|
||||
{
|
||||
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
|
||||
RequireHeaderSymmetry = false
|
||||
};
|
||||
|
||||
//
|
||||
forwardOptions.KnownNetworks.Clear();
|
||||
forwardOptions.KnownProxies.Clear();
|
||||
|
||||
//
|
||||
// ref: https://github.com/aspnet/Docs/issues/2384
|
||||
source.UseForwardedHeaders(forwardOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using xIdentityModels;
|
||||
using xIdentityModels.Models;
|
||||
using xIdentityModels.Navigations;
|
||||
|
||||
namespace xIds.DbContext
|
||||
{
|
||||
public class XIdentityDbContext : IdentityDbContext
|
||||
{
|
||||
//
|
||||
#region Props/DbSets ...
|
||||
public DbSet<XToken> Tokens { get; set; }
|
||||
public DbSet<XDevice> Devices { get; set; }
|
||||
public DbSet<XProfileImage> Avatars { get; set; }
|
||||
public DbSet<XBannedDevice> BannedDevices { get; set; }
|
||||
public DbSet<XFriendshipFollower> Followers { get; set; }
|
||||
public DbSet<XFriendshipFollowing> Followings { get; set; }
|
||||
public DbSet<XVerificationRequest> VerificationRequests { get; set; }
|
||||
#endregion
|
||||
|
||||
public XIdentityDbContext(DbContextOptions<XIdentityDbContext> options) : base(options)
|
||||
{
|
||||
//
|
||||
try
|
||||
{
|
||||
Database.EnsureCreated();
|
||||
Database.Migrate();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
//
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
//
|
||||
// Fix XUser GUID Generator on Add ...
|
||||
modelBuilder
|
||||
.Entity<IdentityUser>()
|
||||
.Property(e => e.Id)
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
//
|
||||
// Handle Role List ...
|
||||
modelBuilder.Entity<XUser>(u =>
|
||||
{
|
||||
u.HasMany(x => x.Roles)
|
||||
.WithOne()
|
||||
.HasForeignKey(ur => ur.UserId)
|
||||
.IsRequired();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MySql.EntityFrameworkCore.Infrastructure;
|
||||
using xCommons.Extensions;
|
||||
using xIdentityModels.Configurations;
|
||||
using xIds.Configurations;
|
||||
using xIds.Constants;
|
||||
using xIds.Models;
|
||||
|
||||
namespace xIds.Extensions
|
||||
{
|
||||
public static class DbExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieve Data Provider Type from Configurations
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
public static XDbProviders GetXDbProviderType(this IConfiguration source)
|
||||
{
|
||||
//
|
||||
var dbProvider = (source[$"{ConfigurationNodeNames.PROVIDER_NODE_NAME}"])
|
||||
.ToNormalString();
|
||||
|
||||
//
|
||||
return dbProvider == ProviderType.SQLServer.ToNormalString() ?
|
||||
XDbProviders.SQLServer :
|
||||
dbProvider == ProviderType.SQLite.ToNormalString() ?
|
||||
XDbProviders.SQLite :
|
||||
dbProvider == ProviderType.MySQL.ToNormalString() ?
|
||||
XDbProviders.MySQL :
|
||||
XDbProviders.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve AspNet Identity Configurations
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
public static XIdentityConfiguration GetXIdentityConfiguration(this IConfiguration source)
|
||||
{
|
||||
//
|
||||
var xIdentityConfigSection = source
|
||||
.GetSection(ConfigurationNodeNames.IDENTITY_NODE_NAME);
|
||||
return xIdentityConfigSection.Get<XIdentityConfiguration>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve XIdentityResource Configuration from AppSettings
|
||||
/// </summary>
|
||||
/// <param name="configuration"></param>
|
||||
/// <returns></returns>
|
||||
public static XIdentityResourceConfiguration GetXIdentityResourceConfiguration(this IConfiguration configuration)
|
||||
{
|
||||
//
|
||||
var xIdentityResourceSection = configuration.GetSection(ConfigurationNodeNames.IDENTITY_RESOURCE_NODE_NAME);
|
||||
return xIdentityResourceSection.Get<XIdentityResourceConfiguration>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register XIdentityResourceConfiguration
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public static void AddXIdentityResourceConfiguration(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration
|
||||
)
|
||||
{
|
||||
//
|
||||
var xIdentityResourceConfiguration = configuration.GetXIdentityResourceConfiguration();
|
||||
if (!xIdentityResourceConfiguration.IsNull())
|
||||
{
|
||||
services.AddSingleton<XIdentityResourceConfiguration>(xIdentityResourceConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts DbInfo Options Builder for MySql Usage
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
public static Action<MySQLDbContextOptionsBuilder> GetMySqlOptionsBuilder(this XDbInfo source)
|
||||
{
|
||||
return ((Action<MySQLDbContextOptionsBuilder>)source.OptionsBuilder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts DbInfo Options Builder for SQLite Usage
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
public static Action<SqliteDbContextOptionsBuilder> GetSQLiteOptionsBuilder(this XDbInfo source)
|
||||
{
|
||||
return ((Action<SqliteDbContextOptionsBuilder>)source.OptionsBuilder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts DbInfo Options Builder for SQLServer Usage
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <returns></returns>
|
||||
public static Action<SqlServerDbContextOptionsBuilder> GetSQLServerOptionsBuilder(this XDbInfo source)
|
||||
{
|
||||
return ((Action<SqlServerDbContextOptionsBuilder>)source.OptionsBuilder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Required Informations to Register DbContexts into Di as XDbInfo instance
|
||||
/// </summary>
|
||||
/// <param name="configuration"></param>
|
||||
/// <returns></returns>
|
||||
public static XDbInfo GetXDbInfo(this IConfiguration configuration)
|
||||
{
|
||||
return new XDbInfo
|
||||
{
|
||||
ProviderType = configuration.GetXDbProviderType(),
|
||||
MigrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepare DbContextOptionsBuilder with Propper data to Support Configured DbProvider
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="dbInfo"></param>
|
||||
/// <param name="connectionString"></param>
|
||||
public static void PrepareXDbContextOptionsBuilder(
|
||||
this DbContextOptionsBuilder source,
|
||||
XDbInfo dbInfo,
|
||||
string connectionString
|
||||
)
|
||||
{
|
||||
//
|
||||
if (dbInfo.ProviderType == XDbProviders.MySQL)
|
||||
{
|
||||
//
|
||||
// Add Support for MySql ...
|
||||
source.UseMySQL(
|
||||
connectionString,
|
||||
dbInfo.GetMySqlOptionsBuilder()
|
||||
);
|
||||
}
|
||||
else if (dbInfo.ProviderType == XDbProviders.SQLite)
|
||||
{
|
||||
//
|
||||
// Add Support for SQLite ...
|
||||
source.UseSqlite(
|
||||
connectionString,
|
||||
dbInfo.GetSQLiteOptionsBuilder()
|
||||
);
|
||||
}
|
||||
else if (dbInfo.ProviderType == XDbProviders.SQLServer)
|
||||
{
|
||||
//
|
||||
// Add Support for SQLServer ...
|
||||
source.UseSqlServer(
|
||||
connectionString,
|
||||
dbInfo.GetSQLServerOptionsBuilder()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using xCommons.Extensions;
|
||||
using xCommons.Models;
|
||||
using xIds.Constants;
|
||||
|
||||
namespace xIds.Extensions
|
||||
{
|
||||
public static class IIdentityServerBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Add Support for Configured XDbProvider to IdentityServer
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <returns></returns>
|
||||
public static IIdentityServerBuilder AddXDbProvider(
|
||||
this IIdentityServerBuilder source,
|
||||
IConfiguration configuration
|
||||
)
|
||||
{
|
||||
//
|
||||
// Retrieve DB Info ...
|
||||
var dbInfo = configuration.GetXDbInfo();
|
||||
dbInfo.OptionsBuilder = (optionsBuilder) =>
|
||||
{
|
||||
optionsBuilder.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
||||
optionsBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
|
||||
};
|
||||
|
||||
//
|
||||
// Retrieve Connection String Names ...
|
||||
var identityDbConnectionString = configuration.GetConnectionString(ConnectionStringNames.IDENTITY_CONNECTION_NAME);
|
||||
var configDbConnectionString = configuration.GetConnectionString(ConnectionStringNames.CONFIGURATION_CONNECTION_NAME);
|
||||
var persistedGrantDbConnectionString = configuration.GetConnectionString(ConnectionStringNames.PRESISTED_GRANTS_CONNECTION_NAME);
|
||||
|
||||
//
|
||||
// Add Operational Store ...
|
||||
source.AddOperationalStore(opt =>
|
||||
{
|
||||
opt.ConfigureDbContext =
|
||||
builder =>
|
||||
{
|
||||
//
|
||||
builder.PrepareXDbContextOptionsBuilder(
|
||||
dbInfo,
|
||||
persistedGrantDbConnectionString
|
||||
);
|
||||
|
||||
//
|
||||
builder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
|
||||
};
|
||||
|
||||
//
|
||||
// this enables automatic token cleanup. this is optional.
|
||||
opt.EnableTokenCleanup = true;
|
||||
opt.TokenCleanupInterval = 3600;
|
||||
});
|
||||
|
||||
//
|
||||
// Add Configuration Store ...
|
||||
source.AddConfigurationStore(opt =>
|
||||
{
|
||||
opt.ConfigureDbContext =
|
||||
builder =>
|
||||
{
|
||||
//
|
||||
builder.PrepareXDbContextOptionsBuilder(
|
||||
dbInfo,
|
||||
configDbConnectionString
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
//
|
||||
return source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set Configured Certificate File to IdentityServer
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <param name="certificate"></param>
|
||||
/// <returns></returns>
|
||||
public static IIdentityServerBuilder LoadSigningCredentialFrom(
|
||||
this IIdentityServerBuilder builder,
|
||||
XCertificate certificate
|
||||
)
|
||||
{
|
||||
//
|
||||
if (!certificate.IsNull() &&
|
||||
!certificate.Path.IsNullOrEmpty() &&
|
||||
!certificate.Secret.IsNullOrEmpty()
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
builder.AddSigningCredential(new X509Certificate2(certificate.Path, certificate.Secret));
|
||||
}
|
||||
catch
|
||||
{
|
||||
builder.AddDeveloperSigningCredential();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AddDeveloperSigningCredential();
|
||||
}
|
||||
|
||||
//
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xModels.Base;
|
||||
using xIds.Constants;
|
||||
|
||||
namespace xIds.Extensions
|
||||
{
|
||||
public static class IQueryableExtensions
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using xIds.Interfaces;
|
||||
using xIds.Providers;
|
||||
|
||||
namespace xIds.Extensions
|
||||
{
|
||||
public static class IdentityExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Register IdentityManager
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
public static void AddXIdentityManager(this IServiceCollection source)
|
||||
{
|
||||
source.AddScoped<IXIdentityManager, XIdentityManager>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register IdentityMessage Provider
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
public static void AddXIdentityMessageProvider(
|
||||
this IServiceCollection source
|
||||
)
|
||||
{
|
||||
source.AddScoped<IXIdentityMessageProvider, XIdentityMessageProvider>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using IdentityServer4.EntityFramework.DbContexts;
|
||||
using IdentityServer4.EntityFramework.Mappers;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Extensions;
|
||||
using xIdentityModels.Descriptors;
|
||||
using xIdentityModels.Extensions;
|
||||
using xIds.Constants;
|
||||
using xIds.Interfaces;
|
||||
using xIds.Models;
|
||||
|
||||
namespace xIds.Extensions
|
||||
{
|
||||
public static class XDbSeeder
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieve DbSeedDescriptor from appSetting Configuration
|
||||
/// </summary>
|
||||
/// <param name="configuration"></param>
|
||||
/// <returns></returns>
|
||||
public static XDbSeedDescriptor GetXDbSeedDescriptor(this IConfiguration configuration)
|
||||
{
|
||||
//
|
||||
var dbSeedSection = configuration.GetSection(ConfigurationNodeNames.DB_SEED_NODE_NAME);
|
||||
return dbSeedSection.Get<XDbSeedDescriptor>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register XDbSeedDescriptor as Singleton Service
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public static void AddXDebSeederDescriptor(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration
|
||||
)
|
||||
{
|
||||
//
|
||||
var dbSeedDescriptor = configuration.GetXDbSeedDescriptor();
|
||||
if (!dbSeedDescriptor.IsNull())
|
||||
{
|
||||
services.AddSingleton<XDbSeedDescriptor>(dbSeedDescriptor);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Error: DbSeeder Configuration not found in AppSetting ...");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add Base Required Data to XIdentitySer DbContexts
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task SeedData(
|
||||
this IApplicationBuilder app,
|
||||
ILogger logger
|
||||
)
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Start Add/Update XIdentityServer Descriptors ...");
|
||||
|
||||
//
|
||||
// Create Scope ...
|
||||
using (var scope = app.ApplicationServices.CreateScope())
|
||||
{
|
||||
//
|
||||
// Retrieve Required Configurations ...
|
||||
var dbSeedDescriptor = scope.ServiceProvider.GetService<XDbSeedDescriptor>();
|
||||
if (dbSeedDescriptor.IsNull())
|
||||
{
|
||||
//
|
||||
Console.WriteLine("DbSeeder is Null ...");
|
||||
return;
|
||||
}
|
||||
logger.LogInformation($"Update Exists Descriptors: {dbSeedDescriptor.UpdateExists.ToString()}");
|
||||
|
||||
//
|
||||
// Retrieve Required Services ...
|
||||
var identityProvider = scope.ServiceProvider.GetService<IXIdentityManager>();
|
||||
|
||||
//
|
||||
// Retrieve DbContexts ...
|
||||
var grantDbContext = scope.ServiceProvider.GetService<PersistedGrantDbContext>();
|
||||
var configDbContext = scope.ServiceProvider.GetService<ConfigurationDbContext>();
|
||||
|
||||
//
|
||||
#region Clients ...
|
||||
//
|
||||
logger.LogInformation($"Start Seeding Clients ...");
|
||||
|
||||
//
|
||||
var dClients = dbSeedDescriptor.Clients;
|
||||
var hasClient = configDbContext.Clients.Any();
|
||||
if ((!hasClient ||
|
||||
(hasClient && dbSeedDescriptor.UpdateExists)) &&
|
||||
dClients.HasChild())
|
||||
{
|
||||
//
|
||||
var clientEntities = dClients.Select(dc => dc.ToEntity());
|
||||
|
||||
//
|
||||
foreach (var client in clientEntities)
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Add/Update: {client.ClientId}");
|
||||
|
||||
//
|
||||
// Retrieve Exists Client ...
|
||||
var existsClient = configDbContext.Clients
|
||||
.Include(c => c.AllowedCorsOrigins)
|
||||
.Include(c => c.AllowedGrantTypes)
|
||||
.Include(c => c.AllowedScopes)
|
||||
.Include(c => c.Claims)
|
||||
.Include(c => c.ClientSecrets)
|
||||
.FirstOrDefault(cl => cl.ClientId == client.ClientId);
|
||||
|
||||
//
|
||||
var isExistsClient = !existsClient.IsNull();
|
||||
var isSameContent = isExistsClient &&
|
||||
existsClient.IsSameContent(client, propertyBlackList: new[] { nameof(existsClient.Id) });
|
||||
|
||||
//
|
||||
if (isExistsClient)
|
||||
{
|
||||
//
|
||||
if (!isSameContent)
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Update Client: {existsClient.ClientId}");
|
||||
|
||||
//
|
||||
existsClient = existsClient.UpdateData(client, propertyBlackList: new[] { nameof(existsClient.Id) });
|
||||
configDbContext.Clients.Update(existsClient);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Add Client: {client.ClientId}");
|
||||
|
||||
//
|
||||
await configDbContext.Clients.AddAsync(client);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Save Changes on Config Db Context ...
|
||||
await configDbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
//
|
||||
logger.LogInformation($"Finish Seeding Clients ...");
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region IdentityResources ...
|
||||
//
|
||||
logger.LogInformation($"Start Seeding Identity Resources ...");
|
||||
|
||||
//
|
||||
var dIdentityResources = dbSeedDescriptor.IdentityResources;
|
||||
var hasIdentityResources = configDbContext.IdentityResources.Any();
|
||||
if ((!hasIdentityResources ||
|
||||
(hasIdentityResources && dbSeedDescriptor.UpdateExists)) &&
|
||||
dIdentityResources.HasChild())
|
||||
{
|
||||
//
|
||||
var identityResourceEntities = dIdentityResources.Select(di => di.ToEntity());
|
||||
|
||||
//
|
||||
foreach (var identityResource in identityResourceEntities)
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Add/Update: {identityResource.DisplayName}");
|
||||
|
||||
//
|
||||
// Retrieve Exists IdentityResource ...
|
||||
var existsIdentityResource = configDbContext.IdentityResources
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault(ir => ir.Name == identityResource.Name);
|
||||
|
||||
//
|
||||
var isExistsResource = !existsIdentityResource.IsNull();
|
||||
var isSameContent = isExistsResource &&
|
||||
existsIdentityResource.IsSameContent(identityResource, propertyBlackList: new[] { nameof(existsIdentityResource.Id) });
|
||||
|
||||
//
|
||||
if (isExistsResource &&
|
||||
dbSeedDescriptor.UpdateExists)
|
||||
{
|
||||
//
|
||||
if (!isSameContent)
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Update IdentityResource: {identityResource.DisplayName}");
|
||||
|
||||
//
|
||||
existsIdentityResource = existsIdentityResource.UpdateData(identityResource, propertyBlackList: new[] { nameof(existsIdentityResource.Id) });
|
||||
configDbContext.IdentityResources.Update(existsIdentityResource);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Add IdentityResource: {identityResource.DisplayName}");
|
||||
|
||||
//
|
||||
await configDbContext.IdentityResources.AddAsync(identityResource);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Save Changes on Config Db Context ...
|
||||
// await configDbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
//
|
||||
logger.LogInformation($"Finish Seeding Identity Resources ...");
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Api Resources ...
|
||||
//
|
||||
logger.LogInformation($"Start Seeding Api Resources ...");
|
||||
|
||||
//
|
||||
var dApiResources = dbSeedDescriptor.ApiResources;
|
||||
var hasApiResources = configDbContext.ApiResources.Any();
|
||||
if ((!hasApiResources ||
|
||||
(hasApiResources && dbSeedDescriptor.UpdateExists)) &&
|
||||
dApiResources.HasChild())
|
||||
{
|
||||
//
|
||||
var apiResourceEntities = dApiResources.Select(da => da.ToEntity());
|
||||
|
||||
//
|
||||
foreach (var apiResource in apiResourceEntities)
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Add/Update: {apiResource.DisplayName}");
|
||||
|
||||
//
|
||||
// Retrieve Exists ApiResource ...
|
||||
var existsApiResource = configDbContext.ApiResources
|
||||
.Include(r => r.Secrets)
|
||||
.Include(r => r.Scopes)
|
||||
.FirstOrDefault(ar => ar.Name == apiResource.Name);
|
||||
|
||||
//
|
||||
var isExistsResource = !existsApiResource.IsNull();
|
||||
var isSameContent = isExistsResource &&
|
||||
existsApiResource.IsSameContent(apiResource, propertyBlackList: new[] { nameof(existsApiResource.Id) });
|
||||
|
||||
//
|
||||
if (isExistsResource &&
|
||||
dbSeedDescriptor.UpdateExists)
|
||||
{
|
||||
//
|
||||
if (!isSameContent)
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Update ApiResource: {existsApiResource.DisplayName}");
|
||||
|
||||
//
|
||||
existsApiResource = existsApiResource.UpdateData(apiResource, propertyBlackList: new[] { nameof(existsApiResource.Id) });
|
||||
configDbContext.ApiResources.Update(existsApiResource);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Add ApiResource: {apiResource.DisplayName}");
|
||||
|
||||
//
|
||||
await configDbContext.ApiResources.AddAsync(apiResource);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Save Changes on Config Db Context ...
|
||||
// await configDbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
//
|
||||
logger.LogInformation($"Finish Seeding Api Resources ...");
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Api Scopes ...
|
||||
//
|
||||
logger.LogInformation($"Start Seeding Scopes ...");
|
||||
|
||||
//
|
||||
var dScopes = dbSeedDescriptor.ApiScopes;
|
||||
var hasScope = configDbContext.ApiScopes.Any();
|
||||
if ((!hasScope ||
|
||||
(hasScope && dbSeedDescriptor.UpdateExists)) &&
|
||||
dScopes.HasChild())
|
||||
{
|
||||
//
|
||||
var apiScopeEntities = dScopes.Select(dc => dc.ToEntity());
|
||||
|
||||
//
|
||||
foreach (var apiScope in apiScopeEntities)
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Add/Update: {apiScope.DisplayName}");
|
||||
|
||||
//
|
||||
// Retrieve Exists Client ...
|
||||
var existsScope = configDbContext.ApiScopes
|
||||
.FirstOrDefault(sc => sc.Name == apiScope.Name);
|
||||
|
||||
//
|
||||
var isExistsScope = !existsScope.IsNull();
|
||||
var isSameContent = isExistsScope &&
|
||||
existsScope.IsSameContent(apiScope, propertyBlackList: new[] { nameof(existsScope.Id) });
|
||||
|
||||
//
|
||||
if (isExistsScope &&
|
||||
dbSeedDescriptor.UpdateExists)
|
||||
{
|
||||
//
|
||||
if (!isSameContent)
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Update ApiScope: {existsScope.Name}");
|
||||
|
||||
//
|
||||
existsScope = existsScope.UpdateData(apiScope, propertyBlackList: new[] { nameof(existsScope.Id) });
|
||||
configDbContext.ApiScopes.Update(existsScope);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Add ApiScope: {apiScope.Name}");
|
||||
|
||||
//
|
||||
await configDbContext.ApiScopes.AddAsync(apiScope);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Save Changes on Config Db Context ...
|
||||
await configDbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
//
|
||||
logger.LogInformation($"Finish Seeding Scopes ...");
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Users ...
|
||||
//
|
||||
logger.LogInformation($"Start Seeding Users ...");
|
||||
|
||||
//
|
||||
var configUsers = dbSeedDescriptor.Users;
|
||||
var hasUser = identityProvider.GetUsersDbSet().Any();
|
||||
if ((!hasUser ||
|
||||
(hasUser && dbSeedDescriptor.UpdateExists)) &&
|
||||
configUsers.HasChild())
|
||||
{
|
||||
foreach (var user in configUsers)
|
||||
{
|
||||
//
|
||||
logger.LogInformation($"Add/Update User: {user.UserName}");
|
||||
|
||||
//
|
||||
var isUserExists = await identityProvider.IsUserExistsAsync(user.UserName);
|
||||
if (isUserExists &&
|
||||
dbSeedDescriptor.UpdateExists)
|
||||
{
|
||||
//
|
||||
var existsUser = await identityProvider.GetUserAsync(user.UserName);
|
||||
var isSame = existsUser.IsSameAs(user);
|
||||
if (!isSame)
|
||||
{
|
||||
//
|
||||
// Update Entity ...
|
||||
existsUser = existsUser.UpdateData(user, propertyWhiteList: new[] {
|
||||
nameof (XIdentityUserDescriptor.FirstName),
|
||||
nameof (XIdentityUserDescriptor.LastName),
|
||||
nameof (XIdentityUserDescriptor.UserName),
|
||||
nameof (XIdentityUserDescriptor.Email),
|
||||
nameof (XIdentityUserDescriptor.EmailConfirmed),
|
||||
nameof (XIdentityUserDescriptor.PhoneNumber),
|
||||
nameof (XIdentityUserDescriptor.PhoneNumberConfirmed),
|
||||
nameof (XIdentityUserDescriptor.IsEnable),
|
||||
nameof (XIdentityUserDescriptor.IsBanned),
|
||||
nameof (XIdentityUserDescriptor.DateOfBirth)
|
||||
}, propertyValueProviders: new[] {
|
||||
new KeyValuePair<string, Func<XIdentityUserDescriptor, object>> (
|
||||
nameof (XIdentityUserDescriptor.DateOfBirth),
|
||||
(user) => DateTime.Parse (user.DateOfBirth))
|
||||
});
|
||||
|
||||
//
|
||||
await identityProvider.UpdateUserAsync(existsUser, false, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await identityProvider.CreateUserAsync(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
logger.LogInformation($"Finish Seeding Users ...");
|
||||
#endregion
|
||||
}
|
||||
|
||||
//
|
||||
logger.LogInformation($"Finish Add/Update XIdentityServer Descriptors ...");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using xCommons.Extensions;
|
||||
using xDataService.Configuration;
|
||||
using xIdentityModels.Models;
|
||||
|
||||
namespace xIds.Extensions
|
||||
{
|
||||
public static class XModelExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Determine a banned time is passed or not
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="delaySeconds"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsDelayTimePassed(
|
||||
this XBannedDevice source,
|
||||
int delaySeconds
|
||||
)
|
||||
{
|
||||
//
|
||||
var passedTime = source.BannedOn.AddSeconds(delaySeconds);
|
||||
|
||||
//
|
||||
var result = DateTime.UtcNow >= passedTime;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applying Filter to IQueryable
|
||||
/// /// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public static async Task<IQueryable<T>> ApplyFilterAsync<T>(
|
||||
this IQueryable<T> source,
|
||||
string filter
|
||||
) where T : class
|
||||
{
|
||||
//
|
||||
// Apply Filter ...
|
||||
if (!filter.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
var items = source.AsAsyncEnumerable();
|
||||
var filteredItems = new List<T>();
|
||||
await
|
||||
foreach (var item in items)
|
||||
{
|
||||
//
|
||||
if (item.GetPropValues()
|
||||
.ToNormalString()
|
||||
.Contains(filter
|
||||
.ToNormalString()))
|
||||
{
|
||||
//
|
||||
filteredItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return filteredItems.AsQueryable();
|
||||
}
|
||||
|
||||
//
|
||||
return source;
|
||||
}
|
||||
|
||||
public static XDataServiceConfiguration ToXDataServiceConfig(this Configurations.XDataServiceConfiguration config)
|
||||
{
|
||||
//
|
||||
var result = new XDataServiceConfiguration();
|
||||
|
||||
//
|
||||
if (!config.IsNullOrDefault())
|
||||
{
|
||||
//
|
||||
result.PagingConfiguration.DefaultPageSize = config.PagingConfiguration.DefaultPageSize;
|
||||
result.PagingConfiguration.MaxAvailablePageSize = config.PagingConfiguration.MaxAvailablePageSize;
|
||||
result.PagingConfiguration.MinAvailablePageSize = config.PagingConfiguration.MinAvailablePageSize;
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,426 @@
|
||||
using System;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using xCommons.Extensions;
|
||||
using xCommons.Providers;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels.Configurations;
|
||||
using xIdentityModels.Extensions;
|
||||
using xIdentityModels.Models;
|
||||
using xIds.Interfaces;
|
||||
|
||||
namespace xIds.Helpers
|
||||
{
|
||||
public class XIdentityHelper : IXIdentityHelper
|
||||
{
|
||||
private readonly XIdentityConfiguration configurations;
|
||||
private readonly JwtSecurityTokenHandler tokenHandler;
|
||||
private readonly XValidationProvider dataValidationHelper;
|
||||
|
||||
public XIdentityHelper(
|
||||
XIdentityConfiguration configurations,
|
||||
XValidationProvider dataValidationHelper
|
||||
)
|
||||
{
|
||||
//
|
||||
this.configurations = configurations;
|
||||
this.tokenHandler = new JwtSecurityTokenHandler();
|
||||
this.dataValidationHelper = dataValidationHelper;
|
||||
}
|
||||
|
||||
//
|
||||
#region Configuration Parser ...
|
||||
/// <summary>
|
||||
/// Generate a Key for Signing JWT Tokens
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public SymmetricSecurityKey GetTokenSecretKey()
|
||||
{
|
||||
//
|
||||
dataValidationHelper
|
||||
.NotEmpty(configurations.IdentitySecretKey);
|
||||
|
||||
//
|
||||
var result = new SymmetricSecurityKey(configurations
|
||||
.IdentitySecretKey.ToBytes());
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate Security Token Signing Key
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public SigningCredentials GetTokenSigningCredentials()
|
||||
{
|
||||
//
|
||||
var key = GetTokenSecretKey();
|
||||
dataValidationHelper
|
||||
.NotNull(key);
|
||||
|
||||
//
|
||||
var result = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Token Validation Parameters
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public TokenValidationParameters GetTokenValidationParams()
|
||||
{
|
||||
//
|
||||
var key = GetTokenSecretKey();
|
||||
var issuer = configurations.IdentityIssuer;
|
||||
var audience = configurations.IdentityAudience;
|
||||
|
||||
//
|
||||
dataValidationHelper
|
||||
.NotNull(key);
|
||||
dataValidationHelper
|
||||
.NotEmpty(issuer, audience);
|
||||
|
||||
//
|
||||
var result = new TokenValidationParameters
|
||||
{
|
||||
ValidIssuer = issuer,
|
||||
ValidAudience = audience,
|
||||
ValidateLifetime = true,
|
||||
IssuerSigningKey = key
|
||||
};
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Account Lockout Time Span after Max Fail Reached
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public TimeSpan GetLockoutTimeSpan()
|
||||
{
|
||||
//
|
||||
dataValidationHelper
|
||||
.NotNull(configurations.Policy, configurations.Policy.Lockout);
|
||||
|
||||
//
|
||||
var timeSpanString = configurations.Policy.Lockout.LockoutTimeSpanProvider;
|
||||
dataValidationHelper
|
||||
.NotEmpty(timeSpanString);
|
||||
|
||||
//
|
||||
var mExpireValue = 0;
|
||||
var mExpireValueStr = timeSpanString.GetDigits();
|
||||
var mExpireUnit = timeSpanString.Replace(mExpireValueStr, "");
|
||||
dataValidationHelper
|
||||
.NotEmpty(mExpireUnit);
|
||||
dataValidationHelper
|
||||
.NotEmpty(mExpireValueStr);
|
||||
|
||||
//
|
||||
var isParsed = int.TryParse(mExpireValueStr, out mExpireValue);
|
||||
|
||||
//
|
||||
switch (mExpireUnit)
|
||||
{
|
||||
case "d":
|
||||
return TimeSpan.FromDays(mExpireValue);
|
||||
|
||||
case "h":
|
||||
return TimeSpan.FromHours(mExpireValue);
|
||||
|
||||
case "m":
|
||||
return TimeSpan.FromMinutes(mExpireValue);
|
||||
|
||||
case "s":
|
||||
return TimeSpan.FromSeconds(mExpireValue);
|
||||
|
||||
case "ms":
|
||||
default:
|
||||
return TimeSpan.FromMilliseconds(mExpireValue);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate Security Token Descriptor for Tokenize another
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public SecurityTokenDescriptor GetActionTokenDescriptor()
|
||||
{
|
||||
//
|
||||
dataValidationHelper
|
||||
.NotNull(configurations);
|
||||
|
||||
//
|
||||
var issuer = configurations.IdentityIssuer;
|
||||
var audience = configurations.IdentityAudience;
|
||||
dataValidationHelper
|
||||
.NotEmpty(issuer, audience);
|
||||
|
||||
//
|
||||
var expDate = GetActionTokenExpirationDate();
|
||||
var signingCreds = GetTokenSigningCredentials();
|
||||
dataValidationHelper
|
||||
.NotNull(expDate, signingCreds);
|
||||
|
||||
//
|
||||
var descriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Issuer = issuer,
|
||||
Audience = audience,
|
||||
Expires = expDate,
|
||||
SigningCredentials = signingCreds
|
||||
};
|
||||
|
||||
//
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Action Token Expiration Date
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public DateTime GetActionTokenExpirationDate()
|
||||
{
|
||||
//
|
||||
dataValidationHelper
|
||||
.NotNull(configurations);
|
||||
|
||||
//
|
||||
var expDateProvider = configurations
|
||||
.ActionTokenExpirationDateProvider;
|
||||
dataValidationHelper
|
||||
.NotEmpty(expDateProvider);
|
||||
|
||||
//
|
||||
var result = GetExpirationTime(expDateProvider);
|
||||
dataValidationHelper
|
||||
.NotNull(result);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Action Token Handlers ...
|
||||
public bool ValidateToken(string token)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
dataValidationHelper
|
||||
.NotEmpty(token);
|
||||
dataValidationHelper
|
||||
.NotNull(tokenHandler);
|
||||
|
||||
//
|
||||
// Prepare Requirements ...
|
||||
var tokenValidationParams = GetTokenValidationParams();
|
||||
dataValidationHelper
|
||||
.NotNull(tokenValidationParams);
|
||||
|
||||
//
|
||||
var result = token
|
||||
.ValidateToken(tokenHandler, tokenValidationParams);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Token string to SecurityToken instance
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public SecurityToken ToSecurityToken(string token)
|
||||
{
|
||||
//
|
||||
dataValidationHelper
|
||||
.NotEmpty(token);
|
||||
|
||||
//
|
||||
// Validate token ...
|
||||
var isTokenValid = ValidateToken(token);
|
||||
if (!isTokenValid)
|
||||
{
|
||||
XException.InvalidToken.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare and Validate Requirements ...
|
||||
var tokenValidationParams = GetTokenValidationParams();
|
||||
dataValidationHelper
|
||||
.NotNull(tokenHandler, tokenValidationParams);
|
||||
|
||||
//
|
||||
var result = token
|
||||
.ToSecurityToken(tokenHandler, tokenValidationParams);
|
||||
dataValidationHelper
|
||||
.NotNull(result);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert an ActionRequest to Token Object
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public SecurityToken ToSecurityToken(XActionRequestToken request)
|
||||
{
|
||||
//
|
||||
var tokenDescriptor = GetActionTokenDescriptor();
|
||||
|
||||
//
|
||||
dataValidationHelper.NotNull(request, tokenHandler, tokenDescriptor);
|
||||
|
||||
//
|
||||
var result = request.ToJwtToken(tokenHandler, tokenDescriptor);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a Token Exiration Date
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public DateTime GetTokenExpirationDate(string token)
|
||||
{
|
||||
//
|
||||
var tokenObj = ToSecurityToken(token);
|
||||
dataValidationHelper.NotNull(tokenObj);
|
||||
|
||||
//
|
||||
var result = tokenObj.ValidTo;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
public XActionRequestToken ParseActionRequestToken(string token)
|
||||
{
|
||||
//
|
||||
dataValidationHelper
|
||||
.NotEmpty(token);
|
||||
|
||||
//
|
||||
// Validate token ...
|
||||
var isTokenValid = ValidateToken(token);
|
||||
if (!isTokenValid)
|
||||
{
|
||||
XException.InvalidToken.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare and Validate Requirements ...
|
||||
var tokenValidationParams = GetTokenValidationParams();
|
||||
dataValidationHelper
|
||||
.NotNull(tokenHandler, tokenValidationParams);
|
||||
|
||||
//
|
||||
var result = token
|
||||
.ParseActionRequestToken(tokenHandler, tokenValidationParams);
|
||||
dataValidationHelper
|
||||
.NotNull(result);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a JWT Security Token Object to
|
||||
/// it's String Representation
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public string ToTokenString(JwtSecurityToken token)
|
||||
{
|
||||
//
|
||||
dataValidationHelper.NotNull(token);
|
||||
|
||||
//
|
||||
var result = tokenHandler
|
||||
.WriteToken(token);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert an Action Token Object to it's String Representation
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public string ToTokenString(SecurityToken token)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
dataValidationHelper
|
||||
.NotNull(token, tokenHandler);
|
||||
|
||||
//
|
||||
// Generate and return Result ...
|
||||
var result = token.ToTokenString(tokenHandler);
|
||||
dataValidationHelper
|
||||
.NotEmpty(result);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Private Actions ...
|
||||
/// <summary>
|
||||
/// Calculating Date Difference Provider String
|
||||
/// and Generate Date based on UTC Time
|
||||
/// </summary>
|
||||
/// <param name="expirationProvider"></param>
|
||||
/// <returns></returns>
|
||||
private DateTime GetExpirationTime(string expirationProvider)
|
||||
{
|
||||
//
|
||||
dataValidationHelper
|
||||
.NotEmpty(expirationProvider);
|
||||
|
||||
//
|
||||
var mExpireValue = 0;
|
||||
var mExpireValueStr = expirationProvider.GetDigits();
|
||||
var mExpireUnit = expirationProvider.Replace(mExpireValueStr, "");
|
||||
dataValidationHelper
|
||||
.NotEmpty(mExpireUnit);
|
||||
dataValidationHelper
|
||||
.NotEmpty(mExpireValueStr);
|
||||
|
||||
//
|
||||
var isParsed = int.TryParse(mExpireValueStr, out mExpireValue);
|
||||
|
||||
//
|
||||
switch (mExpireUnit)
|
||||
{
|
||||
case "d":
|
||||
return DateTime.UtcNow.AddDays(mExpireValue);
|
||||
|
||||
case "h":
|
||||
return DateTime.UtcNow.AddHours(mExpireValue);
|
||||
|
||||
case "m":
|
||||
return DateTime.UtcNow.AddMinutes(mExpireValue);
|
||||
|
||||
case "s":
|
||||
return DateTime.UtcNow.AddSeconds(mExpireValue);
|
||||
|
||||
case "ms":
|
||||
default:
|
||||
return DateTime.UtcNow.AddMilliseconds(mExpireValue);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using xIdentityModels.Models;
|
||||
|
||||
namespace xIds.Interfaces
|
||||
{
|
||||
public interface IXIdentityHelper
|
||||
{
|
||||
//
|
||||
#region Configuration Parser ...
|
||||
SymmetricSecurityKey GetTokenSecretKey();
|
||||
SigningCredentials GetTokenSigningCredentials();
|
||||
TokenValidationParameters GetTokenValidationParams();
|
||||
TimeSpan GetLockoutTimeSpan();
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Action Token Handlers ...
|
||||
bool ValidateToken(string token);
|
||||
SecurityToken ToSecurityToken(string token);
|
||||
SecurityToken ToSecurityToken(XActionRequestToken request);
|
||||
string ToTokenString(SecurityToken token);
|
||||
string ToTokenString(JwtSecurityToken token);
|
||||
DateTime GetTokenExpirationDate(string token);
|
||||
XActionRequestToken ParseActionRequestToken(string token);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,506 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using IdentityModel.Client;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Providers;
|
||||
using xIdentityModels;
|
||||
using xIdentityModels.Constants;
|
||||
using xIdentityModels.Descriptors;
|
||||
using xIdentityModels.Dtos;
|
||||
using xIdentityModels.Models;
|
||||
using xIdentityModels.Navigations;
|
||||
using xIds.DbContext;
|
||||
using xModels.Dtos;
|
||||
|
||||
namespace xIds.Interfaces
|
||||
{
|
||||
public interface IXIdentityManager
|
||||
{
|
||||
XIdentityDbContext DbContext { get; }
|
||||
UserManager<XUser> UserManager { get; }
|
||||
ILogger<IXIdentityManager> Logger { get; }
|
||||
SignInManager<XUser> SignInManager { get; }
|
||||
IXSecurityProvider SecurityProvider { get; }
|
||||
RoleManager<IdentityRole> RoleManager { get; }
|
||||
XValidationProvider ValidationProvider { get; }
|
||||
|
||||
//
|
||||
#region Class Getter (s) Methods ...
|
||||
IQueryable<XUser> GetUsersDbSet(
|
||||
bool containsDetail = false
|
||||
);
|
||||
IQueryable<XUser> GetUsersFullDbSet(bool enableTracking = false);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Tools ...
|
||||
string GetUserSelectByParam(
|
||||
XActionRequest model,
|
||||
bool forceNotNull = true,
|
||||
ICollection<XUserSelectBy> excludes = null
|
||||
);
|
||||
|
||||
Task<XUser> ValidateUserExistsAndRetrieve(
|
||||
string userSelectByParam,
|
||||
bool containsDetail = false,
|
||||
bool checkCanLoginPolicies = false,
|
||||
bool checkIsBanned = true,
|
||||
bool ignoreDisabledUser = false,
|
||||
bool forceAdmin = false,
|
||||
Exception exception = null
|
||||
);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Default Identity Preparation Actions ...
|
||||
Task CreateIdentityRoles();
|
||||
Task CreateUserAsync(XIdentityUserDescriptor user);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Identity Actions ...
|
||||
HttpClient GetHttpClient();
|
||||
Task<IdentityModel.Client.TokenResponse> RequestScopeAccessToken(string scope);
|
||||
Task<DiscoveryDocumentResponse> RequestDiscoveryDocument();
|
||||
Task<IdentityModel.Client.TokenResponse> Authenticate(XLoginRequest model);
|
||||
Task<XLoginResponse> Login(XLoginRequest model);
|
||||
Task<XTokenResponse> RefreshTokens(XTokenResponse model);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Role Handlers ...
|
||||
Task<bool> IsRoleExistsAsync(string roleName);
|
||||
Task<IdentityResult> CreateRoleAsync(string roleName);
|
||||
Task<IdentityRole> GetRoleAsync(string roleName);
|
||||
Task<IdentityResult> AddUserToRoleAsync(XUser user, string roleName);
|
||||
Task<string> GetRoleNameAsync(string roleId);
|
||||
Task<IEnumerable<string>> GetRoleNamesAsync(
|
||||
string userSelectByParam,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
);
|
||||
Task<IdentityResult> RemoveFromRoleAsync(XUser user, string roleName);
|
||||
Task<IdentityResult> RemoveFromRolesAsync(XUser user, IEnumerable<string> roleNames);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region User Handlers ...
|
||||
Task<bool> CanRegister(string userSelectByParam);
|
||||
Task<bool> IsUserExistsAsync(string userSelectByParam);
|
||||
Task<XUser> GetUserAsync(
|
||||
string userSelectByParam,
|
||||
bool containsDetail = false);
|
||||
|
||||
Task<IdentityResult> CreateUserAsync(
|
||||
XUser user,
|
||||
string password,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
);
|
||||
|
||||
Task<IdentityResult> UpdateUserAsync(
|
||||
XUser user,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
);
|
||||
|
||||
Task<IEnumerable<string>> GetUserNamesAsync(
|
||||
IEnumerable<string> userIds
|
||||
);
|
||||
|
||||
Task<IEnumerable<XUserNameIdResponse>> GetUserNameIdsAsync(
|
||||
XUserNameIdRequest model
|
||||
);
|
||||
|
||||
Task<Claim[]> ToJwtClaims(
|
||||
XUser user,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
);
|
||||
|
||||
Task<SignInResult> CheckPasswordSignInAsync(
|
||||
XUser user,
|
||||
string password,
|
||||
XDevice device,
|
||||
string language,
|
||||
bool lockoutOnFailure,
|
||||
bool isForced = true
|
||||
);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region User Profile Handlers ...
|
||||
Task<XUserProfileDto> GetUserProfileAsync(
|
||||
string userSelectByParam,
|
||||
string requestedUserSelectByParam,
|
||||
bool forceCheckRequestedUser = true,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
);
|
||||
|
||||
Task<XQueryResult<XUserProfileDto>> QueryUsers(
|
||||
string requestedUserSelectByParam,
|
||||
XQuery query
|
||||
);
|
||||
|
||||
Task<XQueryResult<XUserProfileDto>> QueryInRoleUsers(
|
||||
string requestedUserSelectByParam,
|
||||
string role,
|
||||
XQuery query,
|
||||
bool forceRole = false
|
||||
);
|
||||
|
||||
Task<IEnumerable<XUserProfileDto>> GetUserProfilesAsync(
|
||||
ICollection<string> ids,
|
||||
string requestedUserSelectByParam,
|
||||
bool forceCheckRequestedUser = true,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
);
|
||||
|
||||
Task<XQueryResult<XProfileImage>> QueryAvatars(
|
||||
string userSelectByParam,
|
||||
XQuery query
|
||||
);
|
||||
|
||||
Task<XUserProfileDto> ProfileUpdateAsync(
|
||||
string userSelectByParam,
|
||||
string requestedUserSelectByParam,
|
||||
XProfileUpdateRequest request
|
||||
);
|
||||
|
||||
Task<XUserProfileDto> FullProfileUpdateAsync(
|
||||
string userSelectByParam,
|
||||
string requestedUserSelectByParam,
|
||||
XProfileUpdateRequest request
|
||||
);
|
||||
|
||||
Task<XActionResponse> RequestConfirmMobile(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string userSelectByParam,
|
||||
string password,
|
||||
string mobileNumber = null
|
||||
);
|
||||
|
||||
Task<XActionResponse> RequestConfirmEmail(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string userSelectByParam,
|
||||
string password,
|
||||
string emailAddress = null
|
||||
);
|
||||
|
||||
Task<XActionResponse> RequestResetPassword(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string userSelectByParam,
|
||||
string returnUrl
|
||||
);
|
||||
|
||||
Task RequestConfirmRegistration(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string userSelectByParam,
|
||||
string password,
|
||||
string returnUrl
|
||||
);
|
||||
|
||||
Task ChangePassword(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string userSelectByParam,
|
||||
string password,
|
||||
string newPassword,
|
||||
string returnUrl
|
||||
);
|
||||
|
||||
Task ResetPassword(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string actionHash,
|
||||
string newPassword,
|
||||
string returnUrl
|
||||
);
|
||||
|
||||
Task<XUserProfileDto> AddAvatar(
|
||||
string userSelectByParam,
|
||||
IFormFile file
|
||||
);
|
||||
|
||||
Task<XUserProfileDto> AddAvatars(
|
||||
string userSelectByParam,
|
||||
IFormFileCollection files
|
||||
);
|
||||
|
||||
Task<XUserProfileDto> SetAvatar(
|
||||
string userSelectByParam,
|
||||
int profileImageId
|
||||
);
|
||||
|
||||
Task<XUserProfileDto> RemoveAvatar(
|
||||
string userSelectByParam,
|
||||
ICollection<int> profileImageIds
|
||||
);
|
||||
|
||||
Task ConfirmRegistration(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string actionHash,
|
||||
string returnUrl
|
||||
);
|
||||
|
||||
Task<XActionResponse> ConfirmMobileNumber(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string registrationHash,
|
||||
string verificationCode
|
||||
);
|
||||
|
||||
Task<XActionResponse> ConfirmEmailAddress(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string registrationHash,
|
||||
string verificationCode
|
||||
);
|
||||
|
||||
Task<bool> IsConfirmedEmail(string userSelectByParam);
|
||||
|
||||
Task<bool> IsConfirmedMobile(string userSelectByParam);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Registration Handlers ...
|
||||
Task<XActionResponse> InviteUser(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string email,
|
||||
string handlerUrl
|
||||
);
|
||||
|
||||
Task<XActionResponse> RequestRegistration(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string invitationHash,
|
||||
string firstName,
|
||||
string lastName,
|
||||
DateTime dateOfBirth,
|
||||
string mobileNumber = null,
|
||||
string emailAddress = null
|
||||
);
|
||||
|
||||
Task<XActionResponse> AddAcountInfo(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string registrationHash,
|
||||
string userName,
|
||||
string password
|
||||
);
|
||||
|
||||
Task<XActionResponse> AttachProfileImage(
|
||||
string tokenHash,
|
||||
IFormFile file
|
||||
);
|
||||
|
||||
Task FinishRegistration(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string userSelectByParam,
|
||||
string password,
|
||||
string returnUrl
|
||||
);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Friendship Handlers ...
|
||||
//
|
||||
#region Actions ...
|
||||
Task<XFriendshipFollowing> Follow(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam
|
||||
);
|
||||
|
||||
Task<bool> Cancel(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam
|
||||
);
|
||||
|
||||
Task UnFollowFollower(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam
|
||||
);
|
||||
|
||||
Task UnFollowFollowing(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam
|
||||
);
|
||||
|
||||
Task<XFriendshipFollowing> Block(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam
|
||||
);
|
||||
|
||||
Task<XFriendshipFollowing> UnBlock(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam
|
||||
);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Request Handlers ...
|
||||
Task<XFriendshipFollower> AcceptRequest(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam
|
||||
);
|
||||
|
||||
Task<XFriendshipFollower> RejectRequest(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam
|
||||
);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Getters ...
|
||||
Task<bool> IsFollower(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam,
|
||||
bool checkIsBanned = true,
|
||||
bool checkCanLoginPolicies = true
|
||||
);
|
||||
|
||||
Task<XFriendshipState> GetFollowerState(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam,
|
||||
bool checkIsBanned = true,
|
||||
bool checkCanLoginPolicies = true
|
||||
);
|
||||
|
||||
Task<XFriendshipFollower> GetFollower(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam
|
||||
);
|
||||
|
||||
Task<IEnumerable<XFriendshipFollower>> GetFollowers(string userSelectByParam);
|
||||
Task<IEnumerable<XFriendshipFollower>> GetAllFollowers(string userSelectByParam);
|
||||
Task<ICollection<string>> GetFollowersList(string userSelectByParam);
|
||||
Task<XQueryResult<XFriendDto>> QueryFollowers(
|
||||
XQuery query,
|
||||
string userSelectByParam
|
||||
);
|
||||
|
||||
Task<bool> IsFollowing(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam,
|
||||
bool checkIsBanned = true,
|
||||
bool checkCanLoginPolicies = true
|
||||
);
|
||||
|
||||
Task<XFriendshipState> GetFollowingState(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam,
|
||||
bool checkIsBanned = true,
|
||||
bool checkCanLoginPolicies = true
|
||||
);
|
||||
|
||||
Task<XFriendshipFollowing> GetFollowing(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam
|
||||
);
|
||||
|
||||
Task<IEnumerable<XFriendshipFollowing>> GetFollowings(string userSelectByParam);
|
||||
Task<IEnumerable<XFriendshipFollowing>> GetAllFollowings(string userSelectByParam);
|
||||
Task<ICollection<string>> GetFollowingList(string userSelectByParam);
|
||||
Task<XQueryResult<XFriendDto>> QueryFollowings(
|
||||
XQuery query,
|
||||
string userSelectByParam
|
||||
);
|
||||
#endregion
|
||||
|
||||
//
|
||||
Task<XFriendshipInfoDto> GetFriendshipInfo(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Admin Actions ...
|
||||
Task<ICollection<string>> Ban(
|
||||
string userSelectByParam,
|
||||
XUserNameIdRequest model
|
||||
);
|
||||
|
||||
Task<ICollection<string>> UnBan(
|
||||
string userSelectByParam,
|
||||
XUserNameIdRequest model
|
||||
);
|
||||
|
||||
Task<bool> IsBanned(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam
|
||||
);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Open Actions ...
|
||||
//
|
||||
#region OpenGet ...
|
||||
Task<XOpenActionInnerDto> OpenGet(
|
||||
XOpenActionInnerDto model
|
||||
);
|
||||
Task<XOpenActionInnerDto> OpenGet(
|
||||
string token,
|
||||
string actionRequest
|
||||
);
|
||||
#endregion
|
||||
|
||||
Task<XOpenActionUserInfoDto> GetUserInfo(
|
||||
XOpenActionRequestDto dto
|
||||
);
|
||||
|
||||
Task<IEnumerable<XOpenActionUserInfoDto>> GetUserInfos(
|
||||
XOpenActionRequestDto dto
|
||||
);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Search ...
|
||||
/// <summary>
|
||||
/// Query Open To Search User Profiles ...
|
||||
/// </summary>
|
||||
/// <param name="requestedUserSelectByParam">requested user's identifier</param>
|
||||
/// <param name="query">how to filter results based on <see>XQuery</see> structure</param>
|
||||
/// <returns>an instance of <see>XQueryResult</see> of <see>XUserProfileDto</see></returns>
|
||||
Task<XQueryResult<XUserProfileDto>> QueryOpenToSearchUsers(
|
||||
string requestedUserSelectByParam,
|
||||
XQuery query
|
||||
);
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Query Service ...
|
||||
/// <summary>
|
||||
/// Retrieve Users as Query Model for Query Service ...
|
||||
/// </summary>
|
||||
/// <param name="requestedUserSelectByParam"></param>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="role"></param>
|
||||
/// <param name="forceRole"></param>
|
||||
/// <returns></returns>
|
||||
public Task<XQueryResult<string>> QueryUsers(
|
||||
string requestedUserSelectByParam,
|
||||
XQuery query,
|
||||
string role = null,
|
||||
bool forceRole = false
|
||||
);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace xIds.Interfaces
|
||||
{
|
||||
public interface IXIdentityMessageProvider
|
||||
{
|
||||
string InviteMsg { get; }
|
||||
string RegistrationApproveMsg { get; }
|
||||
string RegisteredMsg { get; }
|
||||
string VerificationCodeMsg { get; }
|
||||
string ChangePasswordMsg { get; }
|
||||
string PasswordChangedMsg { get; }
|
||||
string NewDeviceLoggedInMsg { get; }
|
||||
|
||||
bool IsReady();
|
||||
void PrepareMessages(string lang);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace xIds.Interfaces
|
||||
{
|
||||
public interface IXSecurityProvider
|
||||
{
|
||||
string Encrypt(string plainText);
|
||||
string Decrypt(string cipherText);
|
||||
string EncryptFromBytes(byte[] textBytes);
|
||||
string DecryptFromBytes(byte[] cipherBytes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using xIds.Constants;
|
||||
|
||||
namespace xIds.Models
|
||||
{
|
||||
public class XDbInfo
|
||||
{
|
||||
private string _migrationAssembly;
|
||||
public XDbProviders ProviderType { get; set; }
|
||||
public string MigrationsAssembly
|
||||
{
|
||||
get
|
||||
{
|
||||
return _migrationAssembly;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
//
|
||||
_migrationAssembly = value;
|
||||
|
||||
//
|
||||
OptionsBuilder = b =>
|
||||
{
|
||||
b.MigrationsAssembly(value);
|
||||
};
|
||||
}
|
||||
}
|
||||
public Action<dynamic> OptionsBuilder { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using IdentityServer4.Models;
|
||||
using xIdentityModels.Descriptors;
|
||||
|
||||
namespace xIds.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// the resource Descriptors for Using on DbSeed
|
||||
/// </summary>
|
||||
public class XDbSeedDescriptor
|
||||
{
|
||||
public bool UpdateExists { get; set; }
|
||||
public ICollection<ApiScope> ApiScopes { get; set; }
|
||||
public ICollection<ApiResource> ApiResources { get; set; }
|
||||
public ICollection<IdentityResource> IdentityResources { get; set; }
|
||||
public ICollection<Client> Clients { get; set; }
|
||||
public ICollection<XIdentityUserDescriptor> Users { get; set; }
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace xIds
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:50046",
|
||||
"sslPort": 44363
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "weatherforecast",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"xIdentityServerApi": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "weatherforecast",
|
||||
"applicationUrl": "https://localhost:4001;http://localhost:4000;https://0.0.0.0:4001;",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using xCommons.Extensions;
|
||||
using xCommons.Providers;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels;
|
||||
using xIdentityModels.Configurations;
|
||||
using xIdentityModels.Constants;
|
||||
using xIdentityModels.Models;
|
||||
using xMessageService.Interfaces;
|
||||
using xStorageService.Interfaces;
|
||||
using xIds.Configurations;
|
||||
using xIds.DbContext;
|
||||
using xIds.Interfaces;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager : IXIdentityManager
|
||||
{
|
||||
//
|
||||
private JsonSerializerSettings jsonSerializerSettings;
|
||||
|
||||
//
|
||||
public XIdentityDbContext DbContext { get; }
|
||||
public UserManager<XUser> UserManager { get; }
|
||||
public IXIdentityHelper IdentityHelper { get; }
|
||||
public ILogger<IXIdentityManager> Logger { get; }
|
||||
public IXMessageProvider MessageProvider { get; }
|
||||
public IXStorageProvider StorageProvider { get; }
|
||||
public SignInManager<XUser> SignInManager { get; }
|
||||
public IXSecurityProvider SecurityProvider { get; }
|
||||
public XIdentityConfiguration Configuration { get; }
|
||||
public RoleManager<IdentityRole> RoleManager { get; }
|
||||
public XValidationProvider ValidationProvider { get; }
|
||||
public XDataServiceConfiguration DataConfiguration { get; }
|
||||
public IXIdentityMessageProvider IdentityMessageProvider { get; }
|
||||
public XIdentityResourceConfiguration IdentityResourceConfiguration { get; }
|
||||
|
||||
public XIdentityManager(
|
||||
XIdentityDbContext dbContext,
|
||||
UserManager<XUser> userManager,
|
||||
IXIdentityHelper identityHelper,
|
||||
ILogger<IXIdentityManager> logger,
|
||||
IXMessageProvider messageProvider,
|
||||
IXStorageProvider storageProvider,
|
||||
SignInManager<XUser> signInManager,
|
||||
IXSecurityProvider securityProvider,
|
||||
XIdentityConfiguration configuration,
|
||||
RoleManager<IdentityRole> roleManager,
|
||||
XValidationProvider validationProvider,
|
||||
XDataServiceConfiguration dataConfiguration,
|
||||
IXIdentityMessageProvider identityMessageProvider,
|
||||
XIdentityResourceConfiguration identityResourceConfiguration
|
||||
)
|
||||
{
|
||||
//
|
||||
Logger = logger;
|
||||
DbContext = dbContext;
|
||||
RoleManager = roleManager;
|
||||
UserManager = userManager;
|
||||
SignInManager = signInManager;
|
||||
SecurityProvider = securityProvider;
|
||||
Configuration = configuration;
|
||||
IdentityHelper = identityHelper;
|
||||
MessageProvider = messageProvider;
|
||||
StorageProvider = storageProvider;
|
||||
DataConfiguration = dataConfiguration;
|
||||
ValidationProvider = validationProvider;
|
||||
IdentityMessageProvider = identityMessageProvider;
|
||||
IdentityResourceConfiguration = identityResourceConfiguration;
|
||||
|
||||
//
|
||||
this.jsonSerializerSettings = new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
#region Class Getter (s) Methods ...
|
||||
/// <summary>
|
||||
/// Retrieve User DB Set
|
||||
/// </summary>
|
||||
/// <param name="containDetails">specifies returned object contains all Navigation Properties or not, default is false</param>
|
||||
/// <returns></returns>
|
||||
public IQueryable<XUser> GetUsersDbSet(
|
||||
bool containDetails = false
|
||||
)
|
||||
{
|
||||
//
|
||||
var dbSet = containDetails ? GetUsersFullDbSet() :
|
||||
UserManager.Users;
|
||||
return dbSet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve User Db Set Full Navigation Properties
|
||||
/// </summary>
|
||||
/// <param name="enableTracking"></param>
|
||||
/// <returns></returns>
|
||||
public IQueryable<XUser> GetUsersFullDbSet(bool enableTracking = false)
|
||||
{
|
||||
//
|
||||
var dbSet = UserManager.Users
|
||||
.Include(u => u.Roles)
|
||||
.Include(u => u.Devices)
|
||||
.Include(u => u.Followers)
|
||||
.Include(u => u.Followings)
|
||||
.Include(u => u.Avatars);
|
||||
|
||||
//
|
||||
return dbSet.AsSplitQuery();
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Tools ...
|
||||
/// <summary>
|
||||
/// Get User SelectBy Param
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="forceNotNull"></param>
|
||||
/// <param name="excludes"></param>
|
||||
/// <returns></returns>
|
||||
public string GetUserSelectByParam(
|
||||
XActionRequest model,
|
||||
bool forceNotNull = true,
|
||||
ICollection<XUserSelectBy> excludes = null
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotNull(model);
|
||||
|
||||
//
|
||||
var id = model.UserId;
|
||||
var userName = model.UserName;
|
||||
var email = model.Email;
|
||||
var phoneNumber = model.MobileNumber;
|
||||
|
||||
//
|
||||
if (excludes != null)
|
||||
{
|
||||
//
|
||||
if (excludes.Contains(XUserSelectBy.ID))
|
||||
{
|
||||
id = null;
|
||||
}
|
||||
if (excludes.Contains(XUserSelectBy.Email))
|
||||
{
|
||||
email = null;
|
||||
}
|
||||
if (excludes.Contains(XUserSelectBy.MobileNumber))
|
||||
{
|
||||
phoneNumber = null;
|
||||
}
|
||||
if (excludes.Contains(XUserSelectBy.Username))
|
||||
{
|
||||
userName = null;
|
||||
}
|
||||
}
|
||||
|
||||
var selectByParam =
|
||||
id.IsNullOrEmpty() ?
|
||||
userName.IsNullOrEmpty() ?
|
||||
email.IsNullOrEmpty() ?
|
||||
phoneNumber.IsNullOrEmpty() ? null : phoneNumber : email : userName : id;
|
||||
|
||||
//
|
||||
// Check result ...
|
||||
if (forceNotNull &&
|
||||
selectByParam.IsNullOrEmpty())
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
return selectByParam;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using xCommons.Extensions;
|
||||
using xIdentityModels.Dtos;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
#region Admin Actions ...
|
||||
/// <summary>
|
||||
/// Retrieve All UnBanned Users Identifiers
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">caller user identifier</param>
|
||||
/// <returns>a collection of user identifiers</returns>
|
||||
public async Task<ICollection<string>> GetAllUnbanned(
|
||||
ICollection<string> userSelectByParam
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = new List<string>();
|
||||
if (!userSelectByParam.HasChild())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
foreach (var uParam in userSelectByParam)
|
||||
{
|
||||
//
|
||||
var destUser = await ValidateUserExistsAndRetrieve(uParam, checkIsBanned: false);
|
||||
if (!destUser.IsBanned)
|
||||
{
|
||||
result.Add(uParam);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get All Banned Users Identifiers
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">caller user identifier</param>
|
||||
/// <returns>a collection of user identifiers</returns>
|
||||
public async Task<ICollection<string>> GetAllBanned(
|
||||
ICollection<string> userSelectByParam
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = new List<string>();
|
||||
if (!userSelectByParam.HasChild())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
foreach (var uParam in userSelectByParam)
|
||||
{
|
||||
//
|
||||
var destUser = await ValidateUserExistsAndRetrieve(uParam, checkIsBanned: false);
|
||||
if (destUser.IsBanned)
|
||||
{
|
||||
result.Add(uParam);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ban a Collection of Users
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">caller user identifier</param>
|
||||
/// <param name="model">an instance of <see>XUserNameIdRequest</see> which represents user identifier list to Ban</param>
|
||||
/// <returns>a collection of user identifiers</returns>
|
||||
public async Task<ICollection<string>> Ban(
|
||||
string userSelectByParam,
|
||||
XUserNameIdRequest model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
ValidationProvider.NotNull(model);
|
||||
ValidationProvider.NotZeroChilds(model.Ids);
|
||||
|
||||
//
|
||||
var user = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
forceAdmin: true,
|
||||
checkIsBanned: true,
|
||||
containDetails: false,
|
||||
ignoreDisabledUser: false,
|
||||
checkCanLoginPolicies: true
|
||||
);
|
||||
|
||||
//
|
||||
var result = new List<string>();
|
||||
foreach (var uParam in model.Ids)
|
||||
{
|
||||
//
|
||||
var destUser = await ValidateUserExistsAndRetrieve(uParam, checkIsBanned: false);
|
||||
|
||||
//
|
||||
var isBanned = destUser.IsBanned;
|
||||
if (!isBanned)
|
||||
{
|
||||
//
|
||||
destUser.IsBanned = true;
|
||||
|
||||
//
|
||||
await UpdateUserAsync(
|
||||
user,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false
|
||||
);
|
||||
|
||||
//
|
||||
result.Add(destUser.Id);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UnBan a Collection of Users
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">caller user identifier</param>
|
||||
/// <param name="model">an instance of <see>XUserNameIdRequest</see> which represents user identifier list to Ban</param>
|
||||
/// <returns>a collection of user identifiers</returns>
|
||||
public async Task<ICollection<string>> UnBan(
|
||||
string userSelectByParam,
|
||||
XUserNameIdRequest model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
ValidationProvider.NotNull(model);
|
||||
ValidationProvider.NotZeroChilds(model.Ids);
|
||||
|
||||
//
|
||||
var user = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
forceAdmin: true,
|
||||
checkIsBanned: true,
|
||||
containDetails: false,
|
||||
ignoreDisabledUser: false,
|
||||
checkCanLoginPolicies: true
|
||||
);
|
||||
|
||||
//
|
||||
var result = new List<string>();
|
||||
foreach (var uParam in model.Ids)
|
||||
{
|
||||
//
|
||||
var destUser = await ValidateUserExistsAndRetrieve(uParam, checkIsBanned: false);
|
||||
|
||||
//
|
||||
var isBanned = destUser.IsBanned;
|
||||
if (isBanned)
|
||||
{
|
||||
//
|
||||
destUser.IsBanned = false;
|
||||
|
||||
//
|
||||
await UpdateUserAsync(
|
||||
user,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false
|
||||
);
|
||||
|
||||
//
|
||||
result.Add(destUser.Id);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detrmines a User is Banned or not
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">caller user identifier</param>
|
||||
/// <param name="destUserSelectByParam">destination user identifier which checked is banned or not</param>
|
||||
/// <returns>a boolean value which represent user banned or not</returns>
|
||||
public async Task<bool> IsBanned(
|
||||
string userSelectByParam,
|
||||
string destUserSelectByParam
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(
|
||||
userSelectByParam,
|
||||
destUserSelectByParam
|
||||
);
|
||||
|
||||
//
|
||||
var user = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
forceAdmin: false,
|
||||
checkIsBanned: true,
|
||||
containDetails: false,
|
||||
ignoreDisabledUser: false,
|
||||
checkCanLoginPolicies: true
|
||||
);
|
||||
var destUser = await ValidateUserExistsAndRetrieve(destUserSelectByParam, checkIsBanned: false);
|
||||
|
||||
//
|
||||
var result = destUser.IsBanned;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,481 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels;
|
||||
using xIdentityModels.Extensions;
|
||||
using xIdentityModels.Models;
|
||||
using xIdentityModels.Navigations;
|
||||
using xIds.Extensions;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Device Actions ...
|
||||
/// <summary>
|
||||
/// Check a Device Exists or Not
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public async Task<bool> IsDeviceExistsAsync(
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
return await DbContext.Devices
|
||||
.AnyAsync(d => d.IsSameAs(device));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add new Device
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns>an instance of <see>XDevice</see></returns>
|
||||
public async Task<XDevice> AddDeviceAsync(
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
//
|
||||
var isDeviceExists = await IsDeviceExistsAsync(device);
|
||||
if (isDeviceExists)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
await DbContext.Devices
|
||||
.AddAsync(device);
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a Device
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns>an instance of <see>XDevice</see></returns>
|
||||
public Task<XDevice> GetDeviceAsync(
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
//
|
||||
return DbContext.Devices
|
||||
.FirstOrDefaultAsync(d =>
|
||||
d.IsSameAs(device));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a List of User Related Devices
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">user identifier</param>
|
||||
/// <param name="checkCanLoginPolicies">check a user can log in in system or not</param>
|
||||
/// <param name="checkIsBanned">check user is banned or not</param>
|
||||
/// <returns>a collection of <see>XDevice</see> instances which related to user</returns>
|
||||
public async Task<ICollection<XDevice>> GetUserDevices(
|
||||
string userSelectByParam,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate ARgs ...
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
|
||||
//
|
||||
// Validate And Retrieve User ...
|
||||
var user = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
containDetails: true,
|
||||
checkCanLoginPolicies: checkCanLoginPolicies,
|
||||
checkIsBanned: checkIsBanned
|
||||
);
|
||||
|
||||
//
|
||||
// Check User Devices ...
|
||||
if (!user.Devices.HasChild())
|
||||
{
|
||||
return new List<XDevice>();
|
||||
}
|
||||
|
||||
//
|
||||
return user.Devices;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines a Device is Exists in User's Devices or not
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public bool IsDeviceRelateDToUser(
|
||||
XUser user,
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
if (!user.Devices.HasChild())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
var result = user.Devices.Any(d => d.IsSameAs(device));
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines a Device is Exists in User's Devices or not
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">user identifier</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="checkCanLoginPolicies">check a user can log in in system or not</param>
|
||||
/// <param name="checkIsBanned">check user is banned or not</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public async Task<bool> IsDeviceRelateDToUser(
|
||||
string userSelectByParam,
|
||||
XDevice device,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
ValidationProvider.NotNull(device);
|
||||
|
||||
//
|
||||
var userDevices = await GetUserDevices(
|
||||
userSelectByParam,
|
||||
checkCanLoginPolicies: checkCanLoginPolicies,
|
||||
checkIsBanned: checkIsBanned
|
||||
);
|
||||
if (!userDevices.HasChild())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
var result = userDevices.Any(d => d.IsSameAs(device));
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a Device to a User Related Devices
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public async Task<bool> AddUserRelatedDevice(
|
||||
XUser user,
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
//
|
||||
var isExists = user.Devices.Any(d =>
|
||||
d.IsSameAs(device));
|
||||
if (isExists)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
user.Devices.Add(device);
|
||||
try
|
||||
{
|
||||
var result = await UpdateUserAsync(user);
|
||||
return result.Succeeded;
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw XException.ActionFailed.ToException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a Device to a User
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">user identifier</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="checkCanLoginPolicies">check a user can log in in system or not</param>
|
||||
/// <param name="checkIsBanned">check user is banned or not</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public async Task<bool> AddUserRelatedDevice(
|
||||
string userSelectByParam,
|
||||
XDevice device,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
ValidationProvider.NotNull(device);
|
||||
|
||||
//
|
||||
// Check Device Related ...
|
||||
var isDeviceRelatedToUser = await IsDeviceRelateDToUser(
|
||||
userSelectByParam,
|
||||
device,
|
||||
checkCanLoginPolicies: checkCanLoginPolicies,
|
||||
checkIsBanned: checkIsBanned);
|
||||
if (isDeviceRelatedToUser)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve User ...
|
||||
var user = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
containDetails: true,
|
||||
checkCanLoginPolicies: checkCanLoginPolicies,
|
||||
checkIsBanned: checkIsBanned
|
||||
);
|
||||
|
||||
//
|
||||
// Add User Device ...
|
||||
user.Devices.Add(device);
|
||||
|
||||
//
|
||||
var result = await UpdateUserAsync(
|
||||
user,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false
|
||||
);
|
||||
|
||||
//
|
||||
return result.Succeeded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a Device from a User Related Devices List
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public async Task<bool> RemoveUserRelatedDevice(
|
||||
XUser user,
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
//
|
||||
var isRelated = IsDeviceRelateDToUser(user, device);
|
||||
if (!isRelated)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
var instanse = user.Devices
|
||||
.FirstOrDefault(d =>
|
||||
d.IsSameAs(device));
|
||||
|
||||
//
|
||||
user.Devices.Remove(instanse);
|
||||
|
||||
//
|
||||
var result = await UpdateUserAsync(
|
||||
user,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false
|
||||
);
|
||||
|
||||
//
|
||||
return result.Succeeded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a Device from a User Devices
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">user identifier</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="checkCanLoginPolicies">check a user can log in in system or not</param>
|
||||
/// <param name="checkIsBanned">check user is banned or not</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public async Task<bool> RemoveUserRelatedDevice(
|
||||
string userSelectByParam,
|
||||
XDevice device,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
ValidationProvider.NotNull(device);
|
||||
|
||||
//
|
||||
// Validate user exists and Retrieve it based on userselectbyparam ...
|
||||
var user = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
containDetails: true,
|
||||
checkCanLoginPolicies: checkCanLoginPolicies,
|
||||
checkIsBanned: checkIsBanned
|
||||
);
|
||||
|
||||
//
|
||||
return await RemoveUserRelatedDevice(
|
||||
user,
|
||||
device
|
||||
);
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Banned Device Actions ...
|
||||
/// <summary>
|
||||
/// Check a Device is exists in Banned Devices or not
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public async Task<bool> IsBannedDeviceExists(
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = false;
|
||||
var bannedDeviceEnumerable = DbContext.BannedDevices.AsAsyncEnumerable();
|
||||
await
|
||||
foreach (var bannedDevice in bannedDeviceEnumerable)
|
||||
{
|
||||
//
|
||||
if (bannedDevice.Device.IsSameAs(device))
|
||||
{
|
||||
//
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find First Banned Device
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns>an instance of <see>XDevice</see></returns>
|
||||
public async Task<XBannedDevice> BannedDeviceFindOne(
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = await DbContext.BannedDevices
|
||||
.FirstOrDefaultAsync(bd =>
|
||||
bd.Device.IsSameAs(device)
|
||||
);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove Banned Device
|
||||
/// </summary>
|
||||
/// <param name="model">an instance of <see>XBannedDevice</see></param>
|
||||
/// <returns></returns>
|
||||
public async Task BannedDeviceRemove(
|
||||
XBannedDevice model
|
||||
)
|
||||
{
|
||||
//
|
||||
var isExists = await IsBannedDeviceExists(model.Device);
|
||||
if (!isExists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
var item = await BannedDeviceFindOne(model.Device);
|
||||
if (item == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
DbContext.BannedDevices.Remove(item);
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a Device is Banned or not
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
private async Task<bool> IsDeviceBanned(
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = await IsBannedDeviceExists(device);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Specific Banned Device
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns>an instance of <see>XBannedDevice</see></returns>
|
||||
private async Task<XBannedDevice> GetBannedDevice(
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = await BannedDeviceFindOne(device);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is a Banned Device passed Banning Time
|
||||
/// </summary>
|
||||
/// <param name="bannedDevice">an instance of <see>XBannedDevice</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
private bool IsDelayTimePassed(
|
||||
XBannedDevice bannedDevice
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (bannedDevice == null ||
|
||||
Configuration == null)
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var isPassed = bannedDevice
|
||||
.IsDelayTimePassed(Configuration.BannedDeviceTimeout);
|
||||
|
||||
//
|
||||
return isPassed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Passed Time from Banning Time of specific Device
|
||||
/// </summary>
|
||||
/// <param name="bannedDevice">an instance of <see>XBannedDevice</see></param>
|
||||
/// <returns>an instance of <see>DateTime</see> which represent Passed Time</returns>
|
||||
private DateTime GetPassedTime(
|
||||
XBannedDevice bannedDevice
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = bannedDevice.BannedOn
|
||||
.AddSeconds(Configuration.BannedDeviceTimeout);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,342 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using IdentityModel.Client;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xExceptions.Models;
|
||||
using xIdentityModels.Extensions;
|
||||
using xIdentityModels.Models;
|
||||
using xIds.Extensions;
|
||||
using static IdentityModel.OidcConstants;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Identity Actions ...
|
||||
/// <summary>
|
||||
/// Request for Discovery Document
|
||||
/// </summary>
|
||||
/// <returns>an instance of <see>DiscoveryDocumentResponse</see></returns>
|
||||
public async Task<DiscoveryDocumentResponse> RequestDiscoveryDocument()
|
||||
{
|
||||
//
|
||||
var httpClient = GetHttpClient();
|
||||
var result = httpClient
|
||||
.GetDiscoveryDocumentAsync(IdentityResourceConfiguration.Authority)
|
||||
.ContinueWith(docTask =>
|
||||
{
|
||||
//
|
||||
httpClient.Dispose();
|
||||
return docTask.Result;
|
||||
});
|
||||
|
||||
//
|
||||
return await result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request AccessToken for Specific XApiScope
|
||||
/// </summary>
|
||||
/// <param name="scope">a member of <see>XApiScope</see></param>
|
||||
/// <returns>an instance of <see>TokenResponse</see></returns>
|
||||
public async Task<IdentityModel.Client.TokenResponse> RequestScopeAccessToken(
|
||||
string scope
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (scope.IsNullOrEmpty())
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve Disco Doc ...
|
||||
var discoDoc = await RequestDiscoveryDocument();
|
||||
if (discoDoc.IsError)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var request = new ClientCredentialsTokenRequest
|
||||
{
|
||||
Address = discoDoc.TokenEndpoint,
|
||||
GrantType = GrantTypes.ClientCredentials,
|
||||
ClientId = IdentityResourceConfiguration.ClientId,
|
||||
ClientSecret = IdentityResourceConfiguration.ClientSecret,
|
||||
Scope = scope
|
||||
};
|
||||
|
||||
//
|
||||
var httpClient = GetHttpClient();
|
||||
var result = await httpClient
|
||||
.RequestClientCredentialsTokenAsync(request)
|
||||
.ContinueWith(response =>
|
||||
{
|
||||
//
|
||||
httpClient.Dispose();
|
||||
return response.Result;
|
||||
});
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authenticate a User
|
||||
/// </summary>
|
||||
/// <param name="model">an instance of <see>XLoginRequest</see> class which represent Authentication requirements</param>
|
||||
/// <returns>an instance of <see>TokenResponse</see></returns>
|
||||
public async Task<IdentityModel.Client.TokenResponse> Authenticate(
|
||||
XLoginRequest model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(model)
|
||||
.AddNotEmpty(
|
||||
model.UserSelectBy,
|
||||
model.Password
|
||||
)
|
||||
.ValidateGroup();
|
||||
|
||||
//
|
||||
// Retrieve Disco Doc ...
|
||||
var discoDoc = await RequestDiscoveryDocument();
|
||||
if (discoDoc.IsError)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Create Request ...
|
||||
var request = new PasswordTokenRequest
|
||||
{
|
||||
//
|
||||
Address = discoDoc.TokenEndpoint,
|
||||
|
||||
//
|
||||
GrantType = GrantTypes.ClientCredentials,
|
||||
ClientId = IdentityResourceConfiguration.ClientId,
|
||||
ClientSecret = IdentityResourceConfiguration.ClientSecret,
|
||||
|
||||
//
|
||||
UserName = model.UserSelectBy,
|
||||
Password = model.Password,
|
||||
|
||||
//
|
||||
// Pass Device to Request ...
|
||||
Parameters = { { "force", false.ToJSON () }
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
var httpClient = GetHttpClient();
|
||||
var result = await httpClient
|
||||
.RequestPasswordTokenAsync(request)
|
||||
.ContinueWith(response =>
|
||||
{
|
||||
//
|
||||
httpClient.Dispose();
|
||||
return response.Result;
|
||||
});
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Do Login based on XLoginRequest
|
||||
/// </summary>
|
||||
/// <param name="model">an instance of <see>XLoginRequest</see> class which represent Authentication requirements</param>
|
||||
/// <returns>an instance of <see>XLoginResponse</see></returns>
|
||||
public async Task<XLoginResponse> Login(
|
||||
XLoginRequest model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(model, model.Device)
|
||||
.AddNotEmpty(
|
||||
model.UserSelectBy,
|
||||
model.Password
|
||||
)
|
||||
.ValidateGroup();
|
||||
|
||||
//
|
||||
// Get Token Response ...
|
||||
//
|
||||
// Retrieve Disco Doc ...
|
||||
var discoDoc = await RequestDiscoveryDocument();
|
||||
Logger.LogInformation($"discoDoc: {discoDoc.ToJSON()}");
|
||||
|
||||
if (discoDoc.IsError)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Create Request ...
|
||||
var request = new PasswordTokenRequest
|
||||
{
|
||||
//
|
||||
Address = discoDoc.TokenEndpoint,
|
||||
|
||||
//
|
||||
GrantType = GrantTypes.ClientCredentials,
|
||||
ClientId = IdentityResourceConfiguration.ClientId,
|
||||
ClientSecret = IdentityResourceConfiguration.ClientSecret,
|
||||
|
||||
//
|
||||
UserName = model.UserSelectBy,
|
||||
Password = model.Password,
|
||||
|
||||
//
|
||||
// Pass Device to Request ...
|
||||
Parameters = { { "force", false.ToJSON () },
|
||||
{ "device", model.Device.ToJSON () },
|
||||
{ "language", model.Language }
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
var httpClient = GetHttpClient();
|
||||
var authResponse = await httpClient
|
||||
.RequestPasswordTokenAsync(request)
|
||||
.ContinueWith(response =>
|
||||
{
|
||||
//
|
||||
httpClient.Dispose();
|
||||
return response.Result;
|
||||
});
|
||||
|
||||
//
|
||||
// Check If Response Has Error ...
|
||||
Logger.LogInformation($"AuthResponse: {authResponse.ToJSON()}");
|
||||
|
||||
//
|
||||
if (authResponse.IsError)
|
||||
{
|
||||
throw authResponse.GetException();
|
||||
}
|
||||
|
||||
//
|
||||
// Create XLoginResponse Model ...
|
||||
var result = authResponse.CreateXLoginResponse();
|
||||
|
||||
//
|
||||
// Get ans Set User Profile ...
|
||||
result.Profile = await GetUserProfileAsync(model.UserSelectBy, model.UserSelectBy);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh Tokens
|
||||
/// </summary>
|
||||
/// <param name="model">Authentication Tokens, instance of <see>XTokenResponse</see></param>
|
||||
/// <returns>an instance of <see>XTokenResponse</see></returns>
|
||||
public async Task<XTokenResponse> RefreshTokens(
|
||||
XTokenResponse model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(model)
|
||||
.AddNotEmpty(
|
||||
model.AccessToken,
|
||||
model.RefreshToken
|
||||
)
|
||||
.ValidateGroup();
|
||||
|
||||
//
|
||||
var authResponse = await RequestDiscoveryDocument()
|
||||
.ContinueWith((discoTask) =>
|
||||
{
|
||||
//
|
||||
var discoDoc = discoTask.Result;
|
||||
if (discoDoc.IsError)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
using (var httpClient = GetHttpClient())
|
||||
{
|
||||
return httpClient.RequestRefreshTokenAsync(new RefreshTokenRequest
|
||||
{
|
||||
//
|
||||
Address = discoDoc.TokenEndpoint,
|
||||
GrantType = GrantTypes.RefreshToken,
|
||||
ClientId = IdentityResourceConfiguration.ClientId,
|
||||
ClientSecret = IdentityResourceConfiguration.ClientSecret,
|
||||
RefreshToken = model.RefreshToken
|
||||
}).Result;
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Check If Response Has Error ...
|
||||
if (authResponse.IsError)
|
||||
{
|
||||
//
|
||||
XError error = authResponse.ErrorDescription.FromJSON<XError>();
|
||||
throw error.ToException();
|
||||
}
|
||||
|
||||
//
|
||||
// Create XLoginResponse Model ...
|
||||
var result = authResponse.CreateXTokenResponse();
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Requirements ...
|
||||
/// <summary>
|
||||
/// Get an Instance of Http Client
|
||||
/// </summary>
|
||||
/// <returns>an instance of <see>HttpClient</see></returns>
|
||||
public HttpClient GetHttpClient()
|
||||
{
|
||||
//
|
||||
HttpClient httpClient = null;
|
||||
httpClient = new HttpClient();
|
||||
var httpClientHandler = new HttpClientHandler()
|
||||
{
|
||||
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
|
||||
{
|
||||
//
|
||||
Logger.LogInformation(
|
||||
$"SSL Handler: {Environment.NewLine} sender: {sender}, {Environment.NewLine} cert: {cert}, {Environment.NewLine} chain: {chain}, {Environment.NewLine} sslPolicyErrors: {sslPolicyErrors}"
|
||||
);
|
||||
|
||||
//
|
||||
return true;
|
||||
},
|
||||
ClientCertificateOptions = ClientCertificateOption.Manual,
|
||||
};
|
||||
|
||||
//
|
||||
httpClient = new HttpClient(httpClientHandler);
|
||||
|
||||
//
|
||||
return httpClient;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
using System;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels.Navigations;
|
||||
using xMessageService.Models;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Message Provider ...
|
||||
/// <summary>
|
||||
/// Generate and Prepare an XMessage Instance for
|
||||
/// User Invite Action
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="emailAddress">reciever email address</param>
|
||||
/// <param name="inviteToken">invitation token</param>
|
||||
/// <param name="returnUrl">return url for invitation user to redirect</param>
|
||||
/// <returns>an instance of <see>XMessage</see></returns>
|
||||
private XMessage GetUserInviteMessage(
|
||||
string lang,
|
||||
string emailAddress,
|
||||
string inviteToken,
|
||||
string returnUrl
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider
|
||||
.NotEmpty(lang, emailAddress, inviteToken, returnUrl);
|
||||
ValidationProvider
|
||||
.EmailAddress(emailAddress);
|
||||
ValidationProvider
|
||||
.Url(returnUrl);
|
||||
|
||||
//
|
||||
HandleMessageProviderPreperation(lang);
|
||||
|
||||
//
|
||||
var msgStr = IdentityMessageProvider.InviteMsg +
|
||||
Environment.NewLine +
|
||||
returnUrl +
|
||||
"?t=" +
|
||||
inviteToken;
|
||||
|
||||
//
|
||||
var message = new XMessage
|
||||
{
|
||||
Message = msgStr,
|
||||
};
|
||||
message.Recievers.Add(emailAddress);
|
||||
|
||||
//
|
||||
return message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate and Prepare an XMessage Instance for
|
||||
/// New Device LoggedIn Action
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="emailAddress">reciever email address</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see> which represent user new Device</param>
|
||||
/// <returns>an instance of <see>XMessage</see></returns>
|
||||
private XMessage GetUserNewDeviceLoggedInMessage(
|
||||
string lang,
|
||||
string emailAddress,
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider
|
||||
.NotEmpty(lang, emailAddress);
|
||||
ValidationProvider
|
||||
.EmailAddress(emailAddress);
|
||||
ValidationProvider
|
||||
.NotNull(device);
|
||||
|
||||
//
|
||||
HandleMessageProviderPreperation(lang);
|
||||
|
||||
//
|
||||
// Generate Specific Message ...
|
||||
var msgStr = IdentityMessageProvider.NewDeviceLoggedInMsg +
|
||||
Environment.NewLine +
|
||||
nameof(XDevice.Os) + ": " + device.Os +
|
||||
Environment.NewLine +
|
||||
nameof(XDevice.OsVersion) + ": " + device.OsVersion +
|
||||
Environment.NewLine +
|
||||
nameof(XDevice.Browser) + ": " + device.Browser +
|
||||
Environment.NewLine +
|
||||
nameof(XDevice.UserAgent) + ": " + device.UserAgent;
|
||||
|
||||
//
|
||||
// Create XMessage Instance ...
|
||||
var message = new XMessage
|
||||
{
|
||||
Message = msgStr,
|
||||
};
|
||||
message.Recievers.Add(emailAddress);
|
||||
|
||||
//
|
||||
return message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate and Prepare an XMessage Instance for
|
||||
/// Verification Code Action
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="mobileNumberOrEmail">an string which points to a user email address or mobile number</param>
|
||||
/// <param name="verificationCode">user verification code</param>
|
||||
/// <returns>an instance of <see>XMessage</see></returns>
|
||||
private XMessage GetVerificationCodeMessage(
|
||||
string lang,
|
||||
string mobileNumberOrEmail,
|
||||
string verificationCode
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider
|
||||
.NotEmpty(lang, mobileNumberOrEmail, verificationCode);
|
||||
|
||||
//
|
||||
HandleMessageProviderPreperation(lang);
|
||||
|
||||
//
|
||||
mobileNumberOrEmail = mobileNumberOrEmail.ToNormalString();
|
||||
|
||||
//
|
||||
// Validate Mobile or Email ...
|
||||
var isValidEmail = mobileNumberOrEmail.IsValidEmail();
|
||||
var isValidMobileNumber = mobileNumberOrEmail.IsValidMobileNumber();
|
||||
if (!isValidEmail &&
|
||||
!isValidMobileNumber)
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare Message String ...
|
||||
var msgStr = IdentityMessageProvider.VerificationCodeMsg +
|
||||
Environment.NewLine +
|
||||
verificationCode;
|
||||
|
||||
//
|
||||
// Create XMessage Instance ...
|
||||
var message = new XMessage
|
||||
{
|
||||
Message = msgStr,
|
||||
};
|
||||
message.Recievers.Add(mobileNumberOrEmail);
|
||||
|
||||
//
|
||||
return message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate and Prepare an XMessage Instance for
|
||||
/// Registration Approve Action
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="emailAddress">reciever email address</param>
|
||||
/// <param name="actionToken">a token which approved user action</param>
|
||||
/// <param name="returnUrl">return url for redirect</param>
|
||||
/// <returns>an instance of <see>XMessage</see></returns>
|
||||
private XMessage GetRegistrationConfirmMessage(
|
||||
string lang,
|
||||
string emailAddress,
|
||||
string actionToken,
|
||||
string returnUrl
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider
|
||||
.NotEmpty(lang, emailAddress, actionToken, returnUrl);
|
||||
ValidationProvider
|
||||
.EmailAddress(emailAddress);
|
||||
ValidationProvider
|
||||
.Url(returnUrl);
|
||||
|
||||
//
|
||||
HandleMessageProviderPreperation(lang);
|
||||
|
||||
//
|
||||
// Prepare Message Str ...
|
||||
var msgStr = IdentityMessageProvider.RegistrationApproveMsg +
|
||||
Environment.NewLine +
|
||||
returnUrl +
|
||||
"?t=" +
|
||||
actionToken;
|
||||
|
||||
//
|
||||
var message = new XMessage
|
||||
{
|
||||
Message = msgStr,
|
||||
};
|
||||
message.Recievers.Add(emailAddress);
|
||||
|
||||
//
|
||||
return message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate and Prepare an XMessage Instance for
|
||||
/// Registration Finished Action
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="emailAddress">reciever email address</param>
|
||||
/// <param name="returnUrl">return url for redirect</param>
|
||||
/// <returns>an instance of <see>XMessage</see></returns>
|
||||
private XMessage GetRegistrationFinishedMessage(
|
||||
string lang,
|
||||
string emailAddress,
|
||||
string returnUrl
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider
|
||||
.NotEmpty(lang, emailAddress, returnUrl);
|
||||
ValidationProvider
|
||||
.EmailAddress(emailAddress);
|
||||
ValidationProvider
|
||||
.Url(returnUrl);
|
||||
|
||||
//
|
||||
HandleMessageProviderPreperation(lang);
|
||||
|
||||
//
|
||||
var msgStr = IdentityMessageProvider.RegisteredMsg +
|
||||
Environment.NewLine +
|
||||
returnUrl;
|
||||
|
||||
//
|
||||
var message = new XMessage
|
||||
{
|
||||
Message = msgStr,
|
||||
};
|
||||
message.Recievers.Add(emailAddress);
|
||||
|
||||
//
|
||||
return message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate and Prepare an XMessage Instance for
|
||||
/// Password Changed Action
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="emailAddress">reciever email address</param>
|
||||
/// <param name="returnUrl">return url for redirect</param>
|
||||
/// <param name="throwException">specify throw exceptions on failure or not, default is true</param>
|
||||
/// <returns>an instance of <see>XMessage</see></returns>
|
||||
private XMessage GetPasswordChangedMessage(
|
||||
string lang,
|
||||
string emailAddress,
|
||||
string returnUrl,
|
||||
bool throwException = true
|
||||
)
|
||||
{
|
||||
//
|
||||
if (throwException)
|
||||
{
|
||||
ValidationProvider
|
||||
.NotEmpty(lang, emailAddress, returnUrl);
|
||||
ValidationProvider
|
||||
.EmailAddress(emailAddress);
|
||||
ValidationProvider
|
||||
.Url(returnUrl);
|
||||
}
|
||||
|
||||
//
|
||||
HandleMessageProviderPreperation(lang);
|
||||
|
||||
//
|
||||
var msgStr = IdentityMessageProvider.PasswordChangedMsg +
|
||||
(returnUrl.IsNullOrEmpty() ?
|
||||
"" :
|
||||
Environment.NewLine +
|
||||
returnUrl);
|
||||
|
||||
//
|
||||
var message = new XMessage
|
||||
{
|
||||
Message = msgStr,
|
||||
};
|
||||
message.Recievers.Add(emailAddress);
|
||||
|
||||
//
|
||||
return message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate and Prepare an XMessage Instance for
|
||||
/// Reset Password Action
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="emailAddress">reciever email address</param>
|
||||
/// <param name="actionToken">a token which approved user action</param>
|
||||
/// <param name="returnUrl">return url for redirect</param>
|
||||
/// <returns>an instance of <see>XMessage</see></returns>
|
||||
private XMessage GetResetPasswordMessage(
|
||||
string lang,
|
||||
string emailAddress,
|
||||
string actionToken,
|
||||
string returnUrl
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider
|
||||
.NotEmpty(lang, emailAddress, actionToken, returnUrl);
|
||||
ValidationProvider
|
||||
.EmailAddress(emailAddress);
|
||||
ValidationProvider
|
||||
.Url(returnUrl);
|
||||
|
||||
//
|
||||
HandleMessageProviderPreperation(lang);
|
||||
|
||||
//
|
||||
// Prepare Message Str ...
|
||||
var msgStr = IdentityMessageProvider.ChangePasswordMsg +
|
||||
Environment.NewLine +
|
||||
returnUrl +
|
||||
"?t=" +
|
||||
actionToken;
|
||||
|
||||
//
|
||||
var message = new XMessage
|
||||
{
|
||||
Message = msgStr,
|
||||
};
|
||||
message.Recievers.Add(emailAddress);
|
||||
|
||||
//
|
||||
return message;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels.Dtos;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region OpenGet ...
|
||||
public async Task<XOpenActionInnerDto> OpenGet(
|
||||
XOpenActionInnerDto model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(model)
|
||||
.AddNotEmpty(model.Token)
|
||||
.AddNotEmpty(model.Payload)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
return await OpenGet(
|
||||
token: model.Token,
|
||||
actionRequest: model.Payload
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
public async Task<XOpenActionInnerDto> OpenGet(
|
||||
string token,
|
||||
string actionRequest
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validatr Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotEmpty(token)
|
||||
.AddNotEmpty(actionRequest)
|
||||
.ValidateGroupAsync();
|
||||
//
|
||||
// Try to Decrypt Request ...
|
||||
var requestModel = ParseModel(
|
||||
token: token,
|
||||
request: actionRequest
|
||||
);
|
||||
if (requestModel.IsNull() ||
|
||||
requestModel.Action.IsNullOrEmpty())
|
||||
{
|
||||
XException.BadRequest.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var responseJson = string.Empty;
|
||||
switch (requestModel.Action)
|
||||
{
|
||||
//
|
||||
case XOpenActions.GetUserInfo:
|
||||
//
|
||||
ValidationProvider.NotEmpty(requestModel.Payload);
|
||||
var userInfo = await GetUserInfo(requestModel);
|
||||
if (userInfo.IsNull())
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
responseJson = userInfo.ToJSON();
|
||||
break;
|
||||
|
||||
//
|
||||
case XOpenActions.GetUserInfos:
|
||||
ValidationProvider.NotEmpty(requestModel.Payload);
|
||||
var userInfos = await GetUserInfos(requestModel);
|
||||
if (userInfos.IsNull())
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
responseJson = userInfos.ToJSON();
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Encrypt Json Str ...
|
||||
var responseStr = SecurityProvider.Encrypt(responseJson);
|
||||
requestModel.Payload = responseStr;
|
||||
requestModel.Timestamp = DateTime.UtcNow
|
||||
.AddMinutes(5)
|
||||
.ToTimestamp()
|
||||
.ToString();
|
||||
|
||||
//
|
||||
token = requestModel.ToOpenActionToken();
|
||||
requestModel.Checksum = token;
|
||||
var result = new XOpenActionInnerDto
|
||||
{
|
||||
Token = token,
|
||||
Payload = requestModel.ToJSON()
|
||||
};
|
||||
|
||||
//
|
||||
// Check Result ...
|
||||
if (result.IsNull())
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public async Task<XOpenActionUserInfoDto> GetUserInfo(
|
||||
XOpenActionRequestDto model
|
||||
)
|
||||
{
|
||||
//
|
||||
// Retrieve User Profile ...
|
||||
var userProfile = await GetUserProfileAsync(
|
||||
checkIsBanned: false,
|
||||
checkCanLoginPolicies: false,
|
||||
requestedUserSelectByParam: "",
|
||||
forceCheckRequestedUser: false,
|
||||
userSelectByParam: model.Payload
|
||||
);
|
||||
|
||||
//
|
||||
// Generate a Dynamic Object ...
|
||||
var result = new XOpenActionUserInfoDto
|
||||
{
|
||||
Username = userProfile.UserName,
|
||||
Firstname = userProfile.FirstName,
|
||||
Lastname = userProfile.LastName,
|
||||
Avatar = userProfile.Avatar
|
||||
};
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<XOpenActionUserInfoDto>> GetUserInfos(
|
||||
XOpenActionRequestDto model
|
||||
)
|
||||
{
|
||||
//
|
||||
var ids = model.Payload.ParseListString<string>().ToList();
|
||||
var profiles = await GetUserProfilesAsync(
|
||||
ids: ids,
|
||||
checkIsBanned: false,
|
||||
checkCanLoginPolicies: false,
|
||||
requestedUserSelectByParam: "",
|
||||
forceCheckRequestedUser: false
|
||||
);
|
||||
var result = profiles.Select(x => new XOpenActionUserInfoDto
|
||||
{
|
||||
Avatar = x.Avatar,
|
||||
Username = x.UserName,
|
||||
Lastname = x.LastName,
|
||||
Firstname = x.FirstName,
|
||||
});
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
#region Private ...
|
||||
private XOpenActionRequestDto ParseModel(
|
||||
string token,
|
||||
string request
|
||||
)
|
||||
{
|
||||
//
|
||||
// Decript request to get Json string of request object ...
|
||||
var result = new XOpenActionRequestDto();
|
||||
|
||||
//
|
||||
var jsonStr = SecurityProvider.Decrypt(request);
|
||||
result = jsonStr.FromJSON<XOpenActionRequestDto>();
|
||||
if (result.IsNull() ||
|
||||
!result.Validate() ||
|
||||
token != result.Checksum
|
||||
)
|
||||
{
|
||||
//
|
||||
result = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
var modelChecksum = result.ToOpenActionToken();
|
||||
result =
|
||||
token == modelChecksum
|
||||
? result
|
||||
: null;
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,552 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using xCommons.Extensions;
|
||||
using xCommons.Helpers;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels;
|
||||
using xIdentityModels.Constants;
|
||||
using xIdentityModels.Dtos;
|
||||
using xIdentityModels.Models;
|
||||
using xIdentityModels.Navigations;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Generators ...
|
||||
/// <summary>
|
||||
/// Generate a Random Number ...
|
||||
/// </summary>
|
||||
/// <returns>a long value</returns>
|
||||
private long GenerateRandom()
|
||||
{
|
||||
return new Random().Next(100000, 999999);
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region UserSelectBy Actions ...
|
||||
/// <summary>
|
||||
/// Retrieve UserSelectByType based on Given Info
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">a user identifier</param>
|
||||
/// <param name="forceUserSelectByParamNotEmpty">a boolean value which specify the identifier
|
||||
/// must be specific and not empty, default is true</param>
|
||||
/// <param name="forceUserSelectByTypeMustSpecified">a boolean value which specify the type
|
||||
/// must be specific, default is false</param>
|
||||
/// <returns>a member of <see>XUserSelectBy</see></returns>
|
||||
private XUserSelectBy GetUserSelectByType(
|
||||
string userSelectByParam,
|
||||
bool forceUserSelectByParamNotEmpty = true,
|
||||
bool forceUserSelectByTypeMustSpecified = false
|
||||
)
|
||||
{
|
||||
//
|
||||
if (forceUserSelectByParamNotEmpty)
|
||||
{
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
}
|
||||
|
||||
//
|
||||
var result = XUserSelectBy.NotSpecified;
|
||||
var normalizedString = userSelectByParam.ToNormalString();
|
||||
if (userSelectByParam.IsValidEmail())
|
||||
{
|
||||
//
|
||||
// Find User by Email ...
|
||||
result = XUserSelectBy.Email;
|
||||
}
|
||||
else if (userSelectByParam.IsValidMobileNumber())
|
||||
{
|
||||
//
|
||||
// Find User by Mobile Number ...
|
||||
result = XUserSelectBy.MobileNumber;
|
||||
}
|
||||
else if (userSelectByParam.IsGuid())
|
||||
{
|
||||
//
|
||||
// Find User By it's ID ...
|
||||
result = XUserSelectBy.ID;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// UserName ...
|
||||
result = XUserSelectBy.Username;
|
||||
}
|
||||
|
||||
//
|
||||
if (forceUserSelectByTypeMustSpecified &&
|
||||
result == XUserSelectBy.NotSpecified)
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve UserSelectByParam based on XUser Object
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <param name="forceNotNull">a boolean value which specify the identifier must nut empty,
|
||||
/// and throw exception if it is empty, default is true</param>
|
||||
/// <param name="excludes">a collection of <see>XUserSelectBy</see> members which
|
||||
/// exclude them from result, default is null</param>
|
||||
/// <returns>a user identifier</returns>
|
||||
private string GetUserSelectByParam(
|
||||
XUser user,
|
||||
bool forceNotNull = true,
|
||||
ICollection<XUserSelectBy> excludes = null
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotNull(user);
|
||||
|
||||
//
|
||||
var id = user.Id;
|
||||
var userName = user.UserName;
|
||||
var email = user.Email;
|
||||
var phoneNumber = user.PhoneNumber;
|
||||
|
||||
//
|
||||
if (excludes != null)
|
||||
{
|
||||
if (excludes.Contains(XUserSelectBy.ID))
|
||||
{
|
||||
id = null;
|
||||
}
|
||||
if (excludes.Contains(XUserSelectBy.Email))
|
||||
{
|
||||
email = null;
|
||||
}
|
||||
if (excludes.Contains(XUserSelectBy.MobileNumber))
|
||||
{
|
||||
phoneNumber = null;
|
||||
}
|
||||
if (excludes.Contains(XUserSelectBy.Username))
|
||||
{
|
||||
userName = null;
|
||||
}
|
||||
}
|
||||
|
||||
var selectByParam =
|
||||
id.IsNullOrEmpty() ?
|
||||
userName.IsNullOrEmpty() ?
|
||||
email.IsNullOrEmpty() ?
|
||||
phoneNumber.IsNullOrEmpty() ? null : phoneNumber : email : userName : id;
|
||||
|
||||
//
|
||||
// Check result ...
|
||||
if (forceNotNull &&
|
||||
selectByParam.IsNullOrEmpty())
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
return selectByParam;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve UserSelectByParam based on <see>XActionRequestContext</see> instance
|
||||
/// </summary>
|
||||
/// <param name="context">an instance of <see>XActionRequestContext</see></param>
|
||||
/// <param name="forceNotNull">a boolean value which specify the identifier must nut empty,
|
||||
/// and throw exception if it is empty, default is true</param>
|
||||
/// <param name="excludes">a collection of <see>XUserSelectBy</see> members which
|
||||
/// exclude them from result, default is null</param>
|
||||
/// <returns>a user identifier</returns>
|
||||
private string GetUserSelectByParam(
|
||||
XActionRequestContext context,
|
||||
bool forceNotNull = true,
|
||||
ICollection<XUserSelectBy> excludes = null
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotNull(context);
|
||||
|
||||
//
|
||||
// Generate User SelectBy ...
|
||||
var id = context.UserId;
|
||||
var userName = context.UserName;
|
||||
var email = context.Email;
|
||||
var phoneNumber = context.MobileNumber;
|
||||
|
||||
//
|
||||
if (excludes != null)
|
||||
{
|
||||
//
|
||||
if (excludes.Contains(XUserSelectBy.ID))
|
||||
{
|
||||
id = null;
|
||||
}
|
||||
if (excludes.Contains(XUserSelectBy.Email))
|
||||
{
|
||||
email = null;
|
||||
}
|
||||
if (excludes.Contains(XUserSelectBy.MobileNumber))
|
||||
{
|
||||
phoneNumber = null;
|
||||
}
|
||||
if (excludes.Contains(XUserSelectBy.Username))
|
||||
{
|
||||
userName = null;
|
||||
}
|
||||
}
|
||||
|
||||
var selectByParam =
|
||||
id.IsNullOrEmpty() ?
|
||||
userName.IsNullOrEmpty() ?
|
||||
email.IsNullOrEmpty() ?
|
||||
phoneNumber.IsNullOrEmpty() ? null : phoneNumber : email : userName : id;
|
||||
|
||||
//
|
||||
// Check param ...
|
||||
if (forceNotNull &&
|
||||
selectByParam.IsNullOrEmpty())
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
return selectByParam;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve UserSelectByParam based on <see>XActionRequestToken</see> instance
|
||||
/// </summary>
|
||||
/// <param name="request">an instance of <see>XActionRequestToken</see> which
|
||||
/// provides required informations</param>
|
||||
/// <param name="forceNotNull">a boolean value which specify the identifier must nut empty,
|
||||
/// and throw exception if it is empty, default is true</param>
|
||||
/// <param name="excludes">a collection of <see>XUserSelectBy</see> members which
|
||||
/// exclude them from result, default is null</param>
|
||||
/// <returns>a user identifier</returns>
|
||||
private string GetUserSelectByParam(
|
||||
XActionRequestToken request,
|
||||
bool forceNotNull = true,
|
||||
ICollection<XUserSelectBy> excludes = null
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotNull(request);
|
||||
|
||||
//
|
||||
// Generate User SelectBy ...
|
||||
return GetUserSelectByParam(
|
||||
context: request.Context,
|
||||
forceNotNull: forceNotNull,
|
||||
excludes: excludes
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Available UserSelectByParams from given XUser
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <returns></returns>
|
||||
private ICollection<string> GenerateUserSelectByParams(
|
||||
XUser user
|
||||
)
|
||||
{
|
||||
//
|
||||
if (user == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
var result = new List<string> {
|
||||
user.Id,
|
||||
user.UserName,
|
||||
user.PhoneNumber,
|
||||
user.Email,
|
||||
};
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Required XUserSelectByTypes
|
||||
/// </summary>
|
||||
/// <param name="ignores">a collection of <see>XUserSelectBy</see> members which
|
||||
/// ignored in result</param>
|
||||
/// <returns>a collection of available <see>XUserSelectBy</see> members</returns>
|
||||
private ICollection<XUserSelectBy> GenerateUserSelectByExcludes(
|
||||
ICollection<XUserSelectBy> ignores
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = ObjectHelper
|
||||
.ToEnumerableValues<XUserSelectBy>()
|
||||
.Except(ignores);
|
||||
|
||||
//
|
||||
return result.ToList();
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region XAction Actions ...
|
||||
/// <summary>
|
||||
/// Retrieve Action Result Response based on XToken
|
||||
/// </summary>
|
||||
/// <param name="xToken">an instance of <see>XToken</see></param>
|
||||
/// <returns>an instance of <see>XActionResponse</see></returns>
|
||||
private XActionResponse GetActionResultResponse(
|
||||
XToken xToken
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotNull(xToken);
|
||||
ValidationProvider.NotEmpty(xToken.Hash, xToken.Token);
|
||||
|
||||
//
|
||||
ValidateToken(xToken.Token);
|
||||
|
||||
//
|
||||
var expDate = GetTokenExpirationDate(xToken.Token);
|
||||
ValidationProvider.NotNull(expDate);
|
||||
|
||||
//
|
||||
// Generate Result class ...
|
||||
var result = new XActionResponse
|
||||
{
|
||||
Token = xToken.Hash,
|
||||
Expiration = expDate
|
||||
};
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region XIdentityMessage Actions ...
|
||||
/// <summary>
|
||||
/// Prepare Message Provider and Check it's State
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
private void HandleMessageProviderPreperation(
|
||||
string lang
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider
|
||||
.NotEmpty(lang);
|
||||
|
||||
//
|
||||
// Prepare Identity Messages ...
|
||||
// the PrepareMessageMethod check IsReady of Helper automatically ...
|
||||
IdentityMessageProvider.PrepareMessages(lang);
|
||||
|
||||
//
|
||||
// Check Message Provider ...
|
||||
var isMessageProviderReady = MessageProvider.IsReady(true);
|
||||
if (!isMessageProviderReady)
|
||||
{
|
||||
XException.MessageServiceInitialFailed.Throw();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Friendship Actions ...
|
||||
/// <summary>
|
||||
/// Check Follow Request Sent Before
|
||||
/// from dest to source
|
||||
/// </summary>
|
||||
/// <param name="source">an instance of <see>XUser</see></param>
|
||||
/// <param name="dest">an instance of <see>XUser</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
private bool IsFollowRequested(
|
||||
XUser source,
|
||||
XUser dest
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotNull(source, dest);
|
||||
|
||||
//
|
||||
var result = source.Followings.Any(f => f.DestId == dest.Id);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check Follow Request Sent Before
|
||||
/// from dest to source
|
||||
/// </summary>
|
||||
/// <param name="source">an instance of <see>XUser</see></param>
|
||||
/// <param name="dest">an instance of <see>XUser</see></param>
|
||||
/// <param name="state">a member of <see>XFriendshipState</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
private bool IsFollowRequested(
|
||||
XUser source,
|
||||
XUser dest,
|
||||
XFriendshipState state
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotNull(source, dest);
|
||||
|
||||
//
|
||||
var result = source.Followings
|
||||
.Any(f =>
|
||||
f.DestId == dest.Id &&
|
||||
f.State == state);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts to XFriendDto ...
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<XFriendDto> ToDto(XFriendshipFollower entity)
|
||||
{
|
||||
//
|
||||
XFriendDto result = null;
|
||||
|
||||
//
|
||||
if (entity.IsNull())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Reading Dest User Profile ...
|
||||
var profile = await GetUserProfileAsync(
|
||||
userSelectByParam: entity.DestId,
|
||||
requestedUserSelectByParam: entity.UserId,
|
||||
forceCheckRequestedUser: false,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false
|
||||
);
|
||||
|
||||
//
|
||||
// Preparing Result ...
|
||||
result = new XFriendDto
|
||||
{
|
||||
UserId = profile.UserId,
|
||||
Avatar = profile.Avatar,
|
||||
Username = profile.UserName,
|
||||
Lastname = profile.LastName,
|
||||
Firstname = profile.FirstName,
|
||||
Type = XFriendshipType.Follower,
|
||||
State = profile.FriendshipInfo.FollowerState,
|
||||
};
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts to XFriendDto ...
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<XFriendDto> ToDto(XFriendshipFollowing entity)
|
||||
{
|
||||
//
|
||||
XFriendDto result = null;
|
||||
|
||||
//
|
||||
if (entity.IsNull())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Reading Dest User Profile ...
|
||||
var profile = await GetUserProfileAsync(
|
||||
checkIsBanned: false,
|
||||
checkCanLoginPolicies: false,
|
||||
forceCheckRequestedUser: false,
|
||||
userSelectByParam: entity.DestId,
|
||||
requestedUserSelectByParam: entity.UserId
|
||||
);
|
||||
|
||||
//
|
||||
// Preparing Result ...
|
||||
result = new XFriendDto
|
||||
{
|
||||
UserId = profile.UserId,
|
||||
Avatar = profile.Avatar,
|
||||
Username = profile.UserName,
|
||||
Lastname = profile.LastName,
|
||||
Firstname = profile.FirstName,
|
||||
Type = XFriendshipType.Following,
|
||||
State = profile.FriendshipInfo.FollowingState,
|
||||
};
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region User Profile ...
|
||||
/// <summary>
|
||||
/// Count User's Page
|
||||
/// </summary>
|
||||
/// <param name="pageSize">an integer value which represent page size</param>
|
||||
/// <returns>an inetger value which represent pages count</returns>
|
||||
public async Task<int> UserPagesCount(
|
||||
int pageSize
|
||||
)
|
||||
{
|
||||
//
|
||||
int count = await UserManager.Users.CountAsync();
|
||||
int pagesCount = count / pageSize;
|
||||
|
||||
//
|
||||
if (count % pageSize > 0)
|
||||
{
|
||||
pagesCount++;
|
||||
}
|
||||
|
||||
//
|
||||
return pagesCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Count Avatar's Page
|
||||
/// </summary>
|
||||
/// <param name="pageSize">an integer value which represent page size</param>
|
||||
/// <returns>an inetger value which represent pages count</returns>
|
||||
public async Task<int> ProfileImagePagesCount(
|
||||
int pageSize
|
||||
)
|
||||
{
|
||||
//
|
||||
int count = await DbContext.Avatars.CountAsync();
|
||||
int pagesCount = count / pageSize;
|
||||
|
||||
//
|
||||
if (count % pageSize > 0)
|
||||
{
|
||||
pagesCount++;
|
||||
}
|
||||
|
||||
//
|
||||
return pagesCount;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,110 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xDataService.Extensions;
|
||||
using xIds.Extensions;
|
||||
using xModels.Dtos;
|
||||
using xIdentityModels.Extensions;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieve Users as Query Model for Query Service ...
|
||||
/// </summary>
|
||||
/// <param name="requestedUserSelectByParam"></param>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="role"></param>
|
||||
/// <param name="forceRole"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<XQueryResult<string>> QueryUsers(
|
||||
string requestedUserSelectByParam,
|
||||
XQuery query,
|
||||
string role = null,
|
||||
bool forceRole = false
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validation ...
|
||||
if (query.IsNull())
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Normalize ...
|
||||
query = query.NormalizeQuery(DataConfiguration.ToXDataServiceConfig());
|
||||
|
||||
//
|
||||
// Since in Resourceable Entities we have to Search on Locales
|
||||
// we Must Implement Senario Custom ...
|
||||
var items = GetUsersDbSet()
|
||||
.ToList()
|
||||
.Where(u => !u.ContainsUserSelectByParam(requestedUserSelectByParam))
|
||||
.ToList()
|
||||
.AsEnumerable();
|
||||
|
||||
//
|
||||
var totalItemsCount = items.Count();
|
||||
|
||||
//
|
||||
// Apply Filter ...
|
||||
if (!query.Filter.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
items = items
|
||||
.ApplyFilter(query.Filter);
|
||||
}
|
||||
int filteredItemsCount = items.Count();
|
||||
|
||||
//
|
||||
// Count Pages ...
|
||||
var totalPagesCount = query.CountPages(totalItemsCount);
|
||||
var filteredPagesCount = query.CountPages(filteredItemsCount);
|
||||
|
||||
//
|
||||
// Apply Paging and Sorting ...
|
||||
if (totalItemsCount > 0 &&
|
||||
filteredItemsCount > 0)
|
||||
{
|
||||
//
|
||||
// Apply Sorting ...
|
||||
items = items
|
||||
.ToList()
|
||||
.ApplySorting(
|
||||
query.SortBy,
|
||||
query.IsAscending
|
||||
);
|
||||
|
||||
//
|
||||
// Apply Paging ...
|
||||
items = items
|
||||
.ToList()
|
||||
.ApplyPaging(
|
||||
query.Page,
|
||||
query.PageSize
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Generate Result Object ...
|
||||
// Query = query,
|
||||
var result = new XQueryResult<string>
|
||||
{
|
||||
Items = items
|
||||
.Select(u => u.Id),
|
||||
Page = query.Page,
|
||||
PageSize = query.PageSize,
|
||||
TotalPages = totalPagesCount,
|
||||
TotalItems = totalItemsCount,
|
||||
TotalFilteredPages = filteredPagesCount,
|
||||
TotalFilteredItems = filteredItemsCount
|
||||
};
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,700 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels;
|
||||
using xIdentityModels.Constants;
|
||||
using xIdentityModels.Models;
|
||||
using xIdentityModels.Navigations;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Registration Actions ...
|
||||
/// <summary>
|
||||
/// Invite a User to Register on Dashboard
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="email">which email address is going to invite</param>
|
||||
/// <param name="returnUrl">return url for invitation user to redirect</param>
|
||||
/// <returns>an instance of <see>XActionResponse</see></returns>
|
||||
public async Task<XActionResponse> InviteUser(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string email,
|
||||
string returnUrl
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotEmpty(
|
||||
lang,
|
||||
email,
|
||||
returnUrl
|
||||
)
|
||||
.AddNotNull(device)
|
||||
.AddEmailAddress(email)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
// Check Email is Unique ...
|
||||
await ValidateUserNotExists(email);
|
||||
|
||||
//
|
||||
// Get Request Result ...
|
||||
var result = await ActionRequest(
|
||||
lang,
|
||||
device,
|
||||
email,
|
||||
XAction.Invite,
|
||||
forceCheckContext: false,
|
||||
forceCheckUserExists: false);
|
||||
|
||||
//
|
||||
// Prepare Propper Message ...
|
||||
var xMessage = GetUserInviteMessage(lang, email, result.Token, returnUrl);
|
||||
|
||||
//
|
||||
// Send Message ...
|
||||
try
|
||||
{
|
||||
await MessageProvider.SendMailAsync(xMessage);
|
||||
}
|
||||
catch { }
|
||||
|
||||
//
|
||||
// Send Result ...
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recieve some Basic Informations and Start Registration Proccess
|
||||
/// if they Valid
|
||||
///
|
||||
/// Registration Proccess Starts with Invoking this Action
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="invitationHash">optional, if user invited, this is the invitation token</param>
|
||||
/// <param name="firstName">user's FirstName</param>
|
||||
/// <param name="lastName">user's LastName</param>
|
||||
/// <param name="dateOfBirth">user's dob date</param>
|
||||
/// <param name="mobileNumber">user's Mobile Number</param>
|
||||
/// <param name="emailAddress">user's Email address</param>
|
||||
/// <returns>an instance of <see>XActionResponse</see></returns>
|
||||
public async Task<XActionResponse> RequestRegistration(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string invitationHash,
|
||||
string firstName,
|
||||
string lastName,
|
||||
DateTime dateOfBirth,
|
||||
string mobileNumber = null,
|
||||
string emailAddress = null
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotEmpty(
|
||||
lang,
|
||||
firstName,
|
||||
lastName
|
||||
)
|
||||
.AddNotNull(
|
||||
device,
|
||||
dateOfBirth
|
||||
)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
// Validate Mobile Number if Exists ...
|
||||
if (!mobileNumber.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
ValidationProvider.MobileNumber(mobileNumber);
|
||||
|
||||
//
|
||||
// Check Mobile is Uniqsue ...
|
||||
await ValidateUserNotExists(mobileNumber);
|
||||
}
|
||||
|
||||
//
|
||||
// Validate Email Address if Exists ...
|
||||
if (!emailAddress.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
ValidationProvider.EmailAddress(emailAddress);
|
||||
|
||||
//
|
||||
// Check Email is Unique ...
|
||||
await ValidateUserNotExists(emailAddress);
|
||||
}
|
||||
|
||||
//
|
||||
// Get Related Token and Validate it and
|
||||
// Check Related Configurations ...
|
||||
await ValidateInvitationHash(invitationHash);
|
||||
|
||||
//
|
||||
// Check Device Validation ...
|
||||
await ValidateDeviceForActions(device);
|
||||
|
||||
//
|
||||
// Validate DateOfBirth ...
|
||||
ValidateDateOfBirth(dateOfBirth);
|
||||
|
||||
//
|
||||
// Define Empty Objects for Using ...
|
||||
var userSelectByParam = "";
|
||||
var context = new XActionRequestContext();
|
||||
//
|
||||
context.Lang = lang;
|
||||
context.Device = device;
|
||||
context.LastName = lastName;
|
||||
context.FirstName = firstName;
|
||||
context.DateOfBirth = dateOfBirth;
|
||||
context.MobileNumber = mobileNumber ?? "";
|
||||
context.Email = !emailAddress.IsNullOrEmpty() ? emailAddress.ToNormalString() : "";
|
||||
|
||||
//
|
||||
userSelectByParam = GetUserSelectByParam(context);
|
||||
|
||||
//
|
||||
// Token Data Parsing ...
|
||||
if (!invitationHash.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
// Get Related Token, Validate it and Parse Contains
|
||||
// XAction Request and Validate the Request itself and
|
||||
// Return it ...
|
||||
var inviteRequest = await ValidateAndParseActionHash(invitationHash);
|
||||
|
||||
//
|
||||
// Extract User Select By Param and Type ...
|
||||
userSelectByParam = GetUserSelectByParam(inviteRequest);
|
||||
var userSelectBy = GetUserSelectByType(userSelectByParam);
|
||||
|
||||
//
|
||||
// Check Invitation Only done with Email Address ...
|
||||
if (userSelectBy != XUserSelectBy.Email)
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Check Invited Email and Given Email to be Same ...
|
||||
if (emailAddress.IsNullOrEmpty() ||
|
||||
(!emailAddress.IsNullOrEmpty() &&
|
||||
!emailAddress.IsValidEmail()))
|
||||
{
|
||||
XException.InvalidEmailAddress.Throw();
|
||||
}
|
||||
var isSameEmail = inviteRequest.Context.Email.ToNormalString() == emailAddress.ToNormalString();
|
||||
if (!isSameEmail)
|
||||
{
|
||||
XException.EmailsSame.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Update Context Email for Request Action ...
|
||||
context.Email = userSelectByParam.ToNormalString();
|
||||
context.EmailVerified = true;
|
||||
}
|
||||
|
||||
//
|
||||
var result = await ActionRequest(
|
||||
lang,
|
||||
device,
|
||||
userSelectByParam,
|
||||
XAction.Registration,
|
||||
context,
|
||||
forceCheckUserExists: false
|
||||
);
|
||||
|
||||
//
|
||||
// Remove Invitation Token ...
|
||||
if (!invitationHash.IsNullOrEmpty())
|
||||
{
|
||||
await RemoveTokenByHash(invitationHash);
|
||||
}
|
||||
|
||||
//
|
||||
// Return Result ...
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add User Account Info
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="actionToken">a token which approved user action</param>
|
||||
/// <param name="userName">user name</param>
|
||||
/// <param name="password">assigne password</param>
|
||||
/// <returns>an instance of <see>XActionResponse</see></returns>
|
||||
public async Task<XActionResponse> AddAcountInfo(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string actionToken,
|
||||
string userName,
|
||||
string password
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotEmpty(
|
||||
lang,
|
||||
actionToken,
|
||||
userName,
|
||||
password)
|
||||
.AddNotNull(device)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
// Check Device Validation ...
|
||||
await ValidateDeviceForActions(device);
|
||||
|
||||
//
|
||||
// Validate a UserSelector is Available or not ...
|
||||
await ValidateCanRegister(userName);
|
||||
|
||||
//
|
||||
// Check UserName is Unique ...
|
||||
await ValidateUserNotExists(userName);
|
||||
|
||||
//
|
||||
// Get Related Token to Registration Hash and Validate it,
|
||||
// then Parse XActionRequest Instance from Token ...
|
||||
var request = await ValidateAndParseActionHash(actionToken);
|
||||
|
||||
//
|
||||
// Validate Requeired Data for Register User must be in Action Context ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotNull(
|
||||
request.Context,
|
||||
request.Context.Device,
|
||||
request.Context.DateOfBirth)
|
||||
.AddNotEmpty(
|
||||
request.Context.Email,
|
||||
request.Context.MobileNumber,
|
||||
request.Context.FirstName,
|
||||
request.Context.LastName)
|
||||
.AddEmailAddress(request.Context.Email)
|
||||
.AddMobileNumber(request.Context.MobileNumber)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
// Validate two Device Must Same ...
|
||||
ValidateRequestAndGivenDevices(device, request.Context.Device);
|
||||
|
||||
//
|
||||
// Extract UserSelectByParam from XActionRequest ...
|
||||
var userSelectByParam = GetUserSelectByParam(request);
|
||||
|
||||
//
|
||||
// Validate Request Pointer User doesn't Exists ...
|
||||
await ValidateUserNotExists(userSelectByParam);
|
||||
|
||||
//
|
||||
// Create an Empty Instance of XUser ...
|
||||
var xUser = new XUser();
|
||||
|
||||
//
|
||||
// Start Filling User Fields ...
|
||||
xUser.UserName = userName;
|
||||
xUser.Email = request.Context.Email;
|
||||
xUser.PhoneNumber = request.Context.MobileNumber;
|
||||
|
||||
//
|
||||
xUser.FirstName = request.Context.FirstName;
|
||||
xUser.LastName = request.Context.LastName;
|
||||
xUser.DateOfBirth = request.Context.DateOfBirth;
|
||||
|
||||
//
|
||||
xUser.EmailConfirmed = request.Context.EmailVerified;
|
||||
xUser.PhoneNumberConfirmed = request.Context.MobileVerified;
|
||||
|
||||
//
|
||||
xUser.CreationDate = DateTime.UtcNow;
|
||||
xUser.LastLogin = null;
|
||||
|
||||
//
|
||||
#region Handling New User IsEnable State ...
|
||||
//
|
||||
// By Default New Users will Enables ...
|
||||
xUser.IsEnable = true;
|
||||
xUser.IsBanned = false;
|
||||
|
||||
//
|
||||
// Check Auto Enable Users ...
|
||||
if (Configuration.RequireRegistrationConfirm)
|
||||
{
|
||||
xUser.IsEnable = false;
|
||||
}
|
||||
|
||||
//
|
||||
// Check Auto Confirm Email Users ...
|
||||
if (Configuration.AutoConfirmNewUsersEmail)
|
||||
{
|
||||
xUser.EmailConfirmed = true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
// Check Auto Confirm Phone Number Users ...
|
||||
if (Configuration.AutoConfirmNewUsersPhoneNumber)
|
||||
{
|
||||
xUser.PhoneNumberConfirmed = true;
|
||||
}
|
||||
|
||||
//
|
||||
// Validating given Password ...
|
||||
await ValidatePasswordPolicies(xUser, password);
|
||||
|
||||
//
|
||||
// Now add new User to Database ...
|
||||
var createUserResult = await CreateUserAsync(xUser, password);
|
||||
if (!createUserResult.Succeeded)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Update Request UserId Value ...
|
||||
request.Context.UserId = xUser.Id;
|
||||
request.Context.UserName = xUser.UserName;
|
||||
|
||||
//
|
||||
#region Handling New User Role ...
|
||||
//
|
||||
// Now Try to Assign Default User role ...
|
||||
var isContainsDefaultUserRole = !Configuration.NewUsersRole.IsNullOrEmpty();
|
||||
if (isContainsDefaultUserRole)
|
||||
{
|
||||
//
|
||||
var newUserRoleName = Configuration.NewUsersRole;
|
||||
var isNewUserRoleExists = await IsRoleExistsAsync(newUserRoleName);
|
||||
//
|
||||
// Make Sure New User role Exists ...
|
||||
if (!isNewUserRoleExists)
|
||||
{
|
||||
//
|
||||
// Create Default Roles ...
|
||||
await CreateIdentityRoles();
|
||||
}
|
||||
|
||||
//
|
||||
// Assign User to Role ...
|
||||
var assignNewUserToRoleResult = await AddUserToRoleAsync(xUser, newUserRoleName);
|
||||
if (!assignNewUserToRoleResult.Succeeded)
|
||||
{
|
||||
//
|
||||
// Delete User if Role Assignment Faild ...
|
||||
await UserManager.DeleteAsync(xUser);
|
||||
|
||||
//
|
||||
// Thrown ActionFailed Error ...
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Handle Profile Image ...
|
||||
// Save and Attach Profile Image to User if it's Added Before ...
|
||||
if (!request.Context.UserId.IsNullOrEmpty() &&
|
||||
!request.Context.Thubmnail.IsNull())
|
||||
{
|
||||
//
|
||||
xUser = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
containDetails: true,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false,
|
||||
ignoreDisabledUser: true,
|
||||
exception: XException.NotFound.ToException()
|
||||
);
|
||||
|
||||
//
|
||||
// Handle Saving File and Attach it to User ...
|
||||
var saveResult = await StorageProvider
|
||||
.HandleProfileImageSave(request.Context.Thubmnail);
|
||||
|
||||
//
|
||||
var xProfileImage = new XProfileImage
|
||||
{
|
||||
UserId = request.Context.UserId,
|
||||
Name = saveResult.FileName,
|
||||
Path = saveResult.FilePath,
|
||||
Thumb = saveResult.Thmbnail,
|
||||
ThumbPath = saveResult.ThmbnailPath
|
||||
};
|
||||
|
||||
//
|
||||
xUser.Avatars.Add(xProfileImage);
|
||||
var updateResult = await UpdateUserAsync(
|
||||
xUser,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false
|
||||
);
|
||||
|
||||
//
|
||||
if (updateResult.Succeeded)
|
||||
{
|
||||
//
|
||||
xUser.Avatar = xProfileImage.ThumbPath;
|
||||
await UpdateUserAsync(
|
||||
xUser,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false
|
||||
);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
// Handle Attaching User device ...
|
||||
var xUserDevice = await AddUserRelatedDevice(
|
||||
userSelectByParam,
|
||||
device,
|
||||
checkCanLoginPolicies: false);
|
||||
|
||||
//
|
||||
// Prepare New Token Result Resource,
|
||||
// by Requesting an Action ...
|
||||
var result = await ActionRequest(
|
||||
lang,
|
||||
device,
|
||||
userSelectByParam,
|
||||
XAction.Finish,
|
||||
request.Context,
|
||||
forceCheckUserExists: false
|
||||
);
|
||||
|
||||
//
|
||||
// Remove Previous Token ...
|
||||
await RemoveTokenByHash(actionToken);
|
||||
|
||||
//
|
||||
// Return Result ...
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attach Profile Image
|
||||
/// </summary>
|
||||
/// <param name="actionToken">a token which approved user action</param>
|
||||
/// <param name="file">an instance of <see>IFormFile</see> for user's Avatar</param>
|
||||
/// <returns>an instance of <see>XActionResponse</see></returns>
|
||||
public async Task<XActionResponse> AttachProfileImage(
|
||||
string actionToken,
|
||||
IFormFile file
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotEmpty(actionToken)
|
||||
.AddNotNull(file)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
// Get Related Token to Registration Hash and Validate it,
|
||||
// then Parse XActionRequest Instance from Token ...
|
||||
var request = await ValidateAndParseActionHash(actionToken);
|
||||
|
||||
//
|
||||
// Extract UserSelectByParam from XActionRequest ...
|
||||
var userSelectByParam = GetUserSelectByParam(request);
|
||||
if (userSelectByParam.IsNullOrEmpty())
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Validate Given FormFile as Profile Image ...
|
||||
StorageProvider.ValidateProfileImage(file);
|
||||
|
||||
//
|
||||
request.Context.Thubmnail = file;
|
||||
|
||||
//
|
||||
// Save and Attach Profile Image to User if it's Added Before ...
|
||||
if (!request.Context.UserId.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
var xUser = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
containDetails: true,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false,
|
||||
ignoreDisabledUser: true,
|
||||
exception: XException.NotFound.ToException()
|
||||
);
|
||||
|
||||
//
|
||||
// Handle Saving File and Attach it to User ...
|
||||
var saveResult = await StorageProvider.HandleProfileImageSave(file);
|
||||
|
||||
//
|
||||
var xProfileImage = new XProfileImage
|
||||
{
|
||||
UserId = request.Context.UserId,
|
||||
Name = saveResult.FileName,
|
||||
Path = saveResult.FilePath,
|
||||
Thumb = saveResult.Thmbnail,
|
||||
ThumbPath = saveResult.ThmbnailPath
|
||||
};
|
||||
|
||||
//
|
||||
xUser.Avatars.Add(xProfileImage);
|
||||
var updateResult = await UpdateUserAsync(
|
||||
xUser,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false
|
||||
);
|
||||
|
||||
//
|
||||
if (updateResult.Succeeded)
|
||||
{
|
||||
//
|
||||
xUser.Avatar = xProfileImage.ThumbPath;
|
||||
await UpdateUserAsync(
|
||||
xUser,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Remove Invitation Token ...
|
||||
if (!actionToken.IsNullOrEmpty())
|
||||
{
|
||||
await RemoveTokenByHash(actionToken);
|
||||
}
|
||||
|
||||
//
|
||||
var result = await ActionRequest(
|
||||
request.Context.Lang,
|
||||
request.Context.Device,
|
||||
userSelectByParam,
|
||||
XAction.ProfileAction,
|
||||
request.Context,
|
||||
forceCheckUserExists: false
|
||||
);
|
||||
|
||||
//
|
||||
// Return Result ...
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finishing Registration
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="userSelectByParam">user identifier</param>
|
||||
/// <param name="password">assigne password</param>
|
||||
/// <param name="returnUrl">return url for invitation user to redirect</param>
|
||||
/// <returns></returns>
|
||||
public async Task FinishRegistration(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string userSelectByParam,
|
||||
string password,
|
||||
string returnUrl
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotEmpty(lang, userSelectByParam, password, returnUrl)
|
||||
.AddNotNull(device)
|
||||
.AddUrl(returnUrl)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
// Validate User Exists And Retrieve it ...
|
||||
var xUser = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
containDetails: false,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false,
|
||||
ignoreDisabledUser: true,
|
||||
forceAdmin: false
|
||||
);
|
||||
|
||||
//
|
||||
#region Handling New User Email Notification Senario ...
|
||||
//
|
||||
// Here we Check if User is Enable and Approved Email
|
||||
// send RegisteredMsg and if User is not Enable and
|
||||
// Verify Registration value in Configuration is True
|
||||
// send Verify Registration mail to user and handle it ...
|
||||
if (Configuration.RequireRegistrationConfirm)
|
||||
{
|
||||
//
|
||||
if (xUser.IsEnable)
|
||||
{
|
||||
//
|
||||
// Send Registration Finished Message ...
|
||||
// since in this step we need to prevent errors from
|
||||
// going forward. add this try catch here ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var xMessage = GetRegistrationFinishedMessage(lang, xUser.Email, returnUrl);
|
||||
|
||||
//
|
||||
await MessageProvider.SendMailAsync(xMessage);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Send Registration Confirm Message ...
|
||||
// since in this step we need to prevent errors from
|
||||
// going forward. add this try catch here ...
|
||||
try
|
||||
{
|
||||
//
|
||||
var request = await ActionRequest(
|
||||
lang,
|
||||
device,
|
||||
userSelectByParam,
|
||||
XAction.Finish,
|
||||
forceCheckContext: false,
|
||||
forceCheckUserExists: true);
|
||||
|
||||
//
|
||||
var xMessage = GetRegistrationConfirmMessage(lang, xUser.Email, request.Token, returnUrl);
|
||||
|
||||
//
|
||||
await MessageProvider.SendMailAsync(xMessage);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
// //
|
||||
// await RemoveTokenByDevice (device);
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,722 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels.Constants;
|
||||
using xIdentityModels.Extensions;
|
||||
using xIdentityModels.Models;
|
||||
using xIdentityModels.Navigations;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Action Handlers ...
|
||||
/// <summary>
|
||||
/// Request an Action
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="userSelectByParam">specified user's identifier</param>
|
||||
/// <param name="step">a member of <see>XAction</see> which represent Action Step</param>
|
||||
/// <param name="context">an instance of <see>XActionRequestContext</see> which provides required informations for specified step</param>
|
||||
/// <param name="forceCheckContext">specify checking context, default is false</param>
|
||||
/// <param name="forceCheckUserExists">specify check user exists, default is true</param>
|
||||
/// <param name="forceCheckUserDevice">specify check user and device relation, default is false</param>
|
||||
/// <param name="forceRenewToken">specifies force renew Action Token if it's expired, default is false</param>
|
||||
/// <returns>an instance of <see>XActionResponse</see></returns>
|
||||
private async Task<XActionResponse> ActionRequest(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string userSelectByParam,
|
||||
XAction step,
|
||||
XActionRequestContext context = null,
|
||||
bool forceCheckContext = false,
|
||||
bool forceCheckUserExists = true,
|
||||
bool forceCheckUserDevice = false,
|
||||
bool forceRenewToken = false
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(lang);
|
||||
ValidationProvider.NotNull(device);
|
||||
|
||||
//
|
||||
// Check Device not Banned ...
|
||||
await ValidateDeviceForActions(device);
|
||||
|
||||
//
|
||||
// Check User Exists and Device Relation ...
|
||||
if (forceCheckUserExists)
|
||||
{
|
||||
if (forceCheckUserDevice)
|
||||
{
|
||||
//
|
||||
if (context.Device != null &&
|
||||
!device.IsSameAs(context.Device))
|
||||
{
|
||||
XException.InvalidDevice.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
await ValidateUserAndDeviceRelation(userSelectByParam, device);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ValidateUserExistsAsync(userSelectByParam);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
XToken xToken = null;
|
||||
XActionResponse result = null;
|
||||
XActionRequestToken xRequest = null;
|
||||
|
||||
//
|
||||
var isExists = false;
|
||||
var forceUserSelectByParamNotEmpty = true;
|
||||
switch (step)
|
||||
{
|
||||
case XAction.Registration:
|
||||
//
|
||||
forceUserSelectByParamNotEmpty = false;
|
||||
isExists = await IsTokenExistsByDeviceAndType(device, step);
|
||||
|
||||
//
|
||||
if (isExists)
|
||||
{
|
||||
xToken = await ValidateAndRetieveTokenByDeviceAndType(device, step);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//
|
||||
isExists = await IsTokenExistsByUserAndType(userSelectByParam, step);
|
||||
|
||||
//
|
||||
if (isExists)
|
||||
{
|
||||
xToken = await ValidateAndRetieveTokenByUserAndType(userSelectByParam, step);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
if (isExists)
|
||||
{
|
||||
//
|
||||
var isValidToken = IsValidToken(xToken.Token);
|
||||
if (!isValidToken && !forceRenewToken)
|
||||
{
|
||||
switch (step)
|
||||
{
|
||||
case XAction.Registration:
|
||||
case XAction.Invite:
|
||||
forceRenewToken = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw XException.InvalidToken.ToException();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
if (!isValidToken && forceRenewToken)
|
||||
{
|
||||
await ValidateAndHandleToken(xToken.Token);
|
||||
return await ActionRequest(
|
||||
lang,
|
||||
device,
|
||||
userSelectByParam,
|
||||
step,
|
||||
context,
|
||||
forceCheckContext,
|
||||
forceCheckUserExists,
|
||||
forceCheckUserDevice,
|
||||
forceRenewToken);
|
||||
}
|
||||
|
||||
//
|
||||
xRequest = ValidateAndParseActionToken(xToken.Token);
|
||||
|
||||
//
|
||||
// Check Exists Context ...
|
||||
if (forceCheckContext)
|
||||
{
|
||||
//
|
||||
var isSameContext = xRequest.Context.IsSameAs(context);
|
||||
if (!isSameContext)
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
if (context != null)
|
||||
{
|
||||
//
|
||||
var contextUserSelectByParam = GetUserSelectByParam(
|
||||
context,
|
||||
false,
|
||||
new List<XUserSelectBy> {
|
||||
XUserSelectBy.ID,
|
||||
XUserSelectBy.Email,
|
||||
XUserSelectBy.MobileNumber
|
||||
});
|
||||
var contextLang = context.Lang;
|
||||
var contextDevice = context.Device;
|
||||
|
||||
//
|
||||
// prevent from issues on Registration Request ...
|
||||
if (forceUserSelectByParamNotEmpty)
|
||||
{
|
||||
var userSelectByType = GetUserSelectByType(userSelectByParam);
|
||||
var contextUserSelectByType = GetUserSelectByType(contextUserSelectByParam);
|
||||
if (contextUserSelectByType != userSelectByType)
|
||||
{
|
||||
//
|
||||
var excludesList = GenerateUserSelectByExcludes(new List<XUserSelectBy> { userSelectByType });
|
||||
|
||||
//
|
||||
contextUserSelectByParam = GetUserSelectByParam(context, false, excludesList);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Fix Device Not Same on Invitation and Request
|
||||
if (step == XAction.Registration)
|
||||
{
|
||||
//
|
||||
context.Device = device;
|
||||
contextDevice = context.Device;
|
||||
}
|
||||
|
||||
//
|
||||
// Validate Context Data must be Same as Request Data ...
|
||||
if ((!contextUserSelectByParam.IsNullOrEmpty() &&
|
||||
contextUserSelectByParam != userSelectByParam) ||
|
||||
(!contextLang.IsNullOrEmpty() &&
|
||||
contextLang != lang) ||
|
||||
(contextDevice != null &&
|
||||
!contextDevice.IsSameAs(device)))
|
||||
{
|
||||
XException.InvalidData.Throw();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
context = new XActionRequestContext
|
||||
{
|
||||
Lang = lang,
|
||||
Device = device
|
||||
};
|
||||
|
||||
//
|
||||
// Add Content ...
|
||||
var userSelectByType = GetUserSelectByType(
|
||||
userSelectByParam,
|
||||
forceUserSelectByParamNotEmpty);
|
||||
switch (userSelectByType)
|
||||
{
|
||||
case XUserSelectBy.MobileNumber:
|
||||
context.MobileNumber = userSelectByParam;
|
||||
break;
|
||||
|
||||
case XUserSelectBy.Email:
|
||||
context.Email = userSelectByParam;
|
||||
break;
|
||||
|
||||
case XUserSelectBy.Username:
|
||||
context.UserName = userSelectByParam;
|
||||
break;
|
||||
|
||||
case XUserSelectBy.ID:
|
||||
context.UserId = userSelectByParam;
|
||||
break;
|
||||
|
||||
case XUserSelectBy.NotSpecified:
|
||||
default:
|
||||
if (forceCheckUserExists)
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Generate Registration Request ...
|
||||
xRequest = new XActionRequestToken
|
||||
{
|
||||
Action = step,
|
||||
Context = context
|
||||
};
|
||||
|
||||
//
|
||||
// Add User Id if Exists to Context ...
|
||||
var isUserExists = await IsUserExistsAsync(userSelectByParam);
|
||||
if (isUserExists)
|
||||
{
|
||||
//
|
||||
var user = await GetUserAsync(userSelectByParam);
|
||||
if (user != null)
|
||||
{
|
||||
xRequest.Context.UserId = user.Id;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
xRequest.Prepare(Configuration.IdentitySecretKey);
|
||||
|
||||
//
|
||||
xToken = await HashRequest(
|
||||
xRequest,
|
||||
forceUserSelectByParamNotEmpty);
|
||||
}
|
||||
|
||||
//
|
||||
// When XToken Exists Passed XToken ...
|
||||
result = GetActionResultResponse(xToken);
|
||||
|
||||
//
|
||||
if (result == null)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request a Mobile Verification Code
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="actionToken">a token which approved user action</param>
|
||||
/// <param name="mobileNumber">the mobile number which is going to request a verification code</param>
|
||||
/// <param name="checkMobileInUse">check mobile number is in use or not, default is true</param>
|
||||
/// <returns>an instance of <see>XActionResponse</see></returns>
|
||||
private async Task<XActionResponse> RequestMobileVerificationCode(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string actionToken,
|
||||
string mobileNumber,
|
||||
bool checkMobileInUse = true
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotEmpty(lang, actionToken, mobileNumber)
|
||||
.AddMobileNumber(mobileNumber)
|
||||
.AddNotNull(device)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
// Check Device Validation ...
|
||||
await ValidateDeviceForActions(device);
|
||||
|
||||
//
|
||||
// Check Mobile is Unique ...
|
||||
if (checkMobileInUse)
|
||||
{
|
||||
var isUserExists = await IsUserExistsAsync(mobileNumber);
|
||||
if (isUserExists)
|
||||
{
|
||||
//
|
||||
var xUser = await GetUserAsync(mobileNumber);
|
||||
|
||||
//
|
||||
if (xUser.PhoneNumberConfirmed)
|
||||
{
|
||||
XException.MobileInUsed.Throw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Get Related Token to Registration Hash and Validate it,
|
||||
// then Parse XActionRequest Instance from Token ...
|
||||
var request = await ValidateAndParseActionHash(actionToken);
|
||||
|
||||
//
|
||||
// Validate two Device Must Same ...
|
||||
ValidateRequestAndGiveDevices(device, request.Context.Device);
|
||||
|
||||
//
|
||||
// Extract UserSelectByParam from XActionRequest ...
|
||||
var userSelectByParam = GetUserSelectByParam(
|
||||
request,
|
||||
forceNotNull: false,
|
||||
excludes: new List<XUserSelectBy> {
|
||||
XUserSelectBy.ID,
|
||||
XUserSelectBy.Email,
|
||||
XUserSelectBy.MobileNumber
|
||||
});
|
||||
|
||||
//
|
||||
// if it's null, means user doesn't have Invitation Token
|
||||
// and there is no User Selector ...
|
||||
if (userSelectByParam.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
// Since Mobile is Unique so it can act as a
|
||||
// UserSelector ...
|
||||
userSelectByParam = mobileNumber;
|
||||
}
|
||||
|
||||
//
|
||||
// Define empty Verification Code
|
||||
// and Empty Verification Request ...
|
||||
var verificationCode = "";
|
||||
XVerificationRequest xVerificationRequest = null;
|
||||
|
||||
//
|
||||
// Check Device Request Verification Code before or Not ...
|
||||
var isDeviceRequested = await IsDeviceRequestedForVerificationCodeBefor(device);
|
||||
if (isDeviceRequested)
|
||||
{
|
||||
//
|
||||
// if Requested before, Retrieve XVerification instance by Device from Db
|
||||
// and Validate it ...
|
||||
xVerificationRequest = await ValidateAndRetrieveVerificationRequest(device);
|
||||
|
||||
//
|
||||
if (xVerificationRequest.VerificationCode.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
verificationCode = GenerateRandom().ToString();
|
||||
xVerificationRequest.VerificationCode = verificationCode;
|
||||
|
||||
//
|
||||
await RemoveVerificationCodeRequestByDevice(
|
||||
device,
|
||||
saveChanges: false
|
||||
);
|
||||
await AddVerificationRequest(
|
||||
xVerificationRequest,
|
||||
saveChanges: false
|
||||
);
|
||||
|
||||
//
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
//
|
||||
// if XVerificationRequest is Valid, it must Contain an Alive Verification Code
|
||||
// so retrieve it and assign it ...
|
||||
verificationCode = xVerificationRequest.VerificationCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
verificationCode = GenerateRandom().ToString();
|
||||
}
|
||||
|
||||
//
|
||||
// if it's First Verification Request of given Device
|
||||
// Generate a new Verification Code ...
|
||||
if (verificationCode.IsNullOrEmpty())
|
||||
{
|
||||
verificationCode = GenerateRandom().ToString();
|
||||
}
|
||||
|
||||
//
|
||||
// Check Context Mobile and given Mobile ...
|
||||
if (!request.Context.MobileNumber.IsNullOrEmpty() &&
|
||||
mobileNumber != request.Context.MobileNumber)
|
||||
{
|
||||
XException.InvalidMobileNumber.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Check User Added To Db or Not ...
|
||||
var isAddedUser = !request.Context.UserId.IsNullOrEmpty();
|
||||
if (isAddedUser)
|
||||
{
|
||||
//
|
||||
// Validate User Exists and Retireve User Object ...
|
||||
var user = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
containDetails: false,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false);
|
||||
|
||||
//
|
||||
// Check Mobiles Same ...
|
||||
if (user.PhoneNumber == mobileNumber &&
|
||||
user.PhoneNumberConfirmed)
|
||||
{
|
||||
XException.MobilesSame.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Update User Object's Mobile Number and
|
||||
// Confirmation Status ...
|
||||
user.PhoneNumber = mobileNumber;
|
||||
user.PhoneNumberConfirmed = false;
|
||||
|
||||
//
|
||||
// Save Changes to Db ...
|
||||
await UpdateUserAsync(user, checkCanLoginPolicies: false, checkIsBanned: false);
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare Verification Request by Checking Next Tries,
|
||||
// Device Status, and etc, Update or Add XVerificationRequest to db
|
||||
// and Retrieve the added Entity ...
|
||||
xVerificationRequest = await HandleVerificationRequestPreparation(verificationCode, request);
|
||||
|
||||
//
|
||||
// Update Request Context MobileNumber
|
||||
// and it's Confirmation Status ...
|
||||
request.Context.MobileNumber = mobileNumber;
|
||||
request.Context.MobileVerified = false;
|
||||
|
||||
//
|
||||
// Remove Previous Token ...
|
||||
await RemoveTokenByHash(actionToken);
|
||||
|
||||
//
|
||||
// Prepare New Token Result Resource,
|
||||
// by Requesting an Action ...
|
||||
var result = await ActionRequest(
|
||||
lang,
|
||||
device,
|
||||
userSelectByParam,
|
||||
XAction.RequestMobileVerificationCode,
|
||||
request.Context,
|
||||
forceCheckUserExists: isAddedUser
|
||||
);
|
||||
|
||||
//
|
||||
// Prepare Message ...
|
||||
var xMessage = GetVerificationCodeMessage(lang, mobileNumber, verificationCode);
|
||||
|
||||
//
|
||||
// Send Verification Code Message to User Using SMS Provider ...
|
||||
await MessageProvider.SendSmsAsync(xMessage, throwException: false);
|
||||
|
||||
//
|
||||
// Return Result ...
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request a Email Verification Code
|
||||
/// </summary>
|
||||
/// <param name="lang">specify destination language</param>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="actionToken">a token which approved user action</param>
|
||||
/// <param name="emailAddress">the email address which is going to request a verification code</param>
|
||||
/// <param name="checkEmailInUse">check email address is in use or not, default is true</param>
|
||||
/// <returns>an instance of <see>XActionResponse</see></returns>
|
||||
public async Task<XActionResponse> RequestEmailVerificationCode(
|
||||
string lang,
|
||||
XDevice device,
|
||||
string actionToken,
|
||||
string emailAddress,
|
||||
bool checkEmailInUse = true
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
await ValidationProvider
|
||||
.GroupValidationBuilder()
|
||||
.AddNotEmpty(lang, actionToken, emailAddress)
|
||||
.AddEmailAddress(emailAddress)
|
||||
.AddNotNull(device)
|
||||
.ValidateGroupAsync();
|
||||
|
||||
//
|
||||
// Check Device Validation ...
|
||||
await ValidateDeviceForActions(device);
|
||||
|
||||
//
|
||||
// Check Email is Unique ...
|
||||
if (checkEmailInUse)
|
||||
{
|
||||
var isUserExists = await IsUserExistsAsync(emailAddress);
|
||||
if (isUserExists)
|
||||
{
|
||||
//
|
||||
var xUser = await GetUserAsync(emailAddress);
|
||||
|
||||
//
|
||||
if (xUser.EmailConfirmed)
|
||||
{
|
||||
XException.EmailInUsed.Throw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Get Related Token to Registration Hash and Validate it,
|
||||
// then Parse XActionRequest Instance from Token ...
|
||||
var request = await ValidateAndParseActionHash(actionToken);
|
||||
|
||||
//
|
||||
// Validate two Device Must Same ...
|
||||
ValidateRequestAndGiveDevices(device, request.Context.Device);
|
||||
|
||||
//
|
||||
// Extract UserSelectByParam from XActionRequest ...
|
||||
var userSelectByParam = GetUserSelectByParam(
|
||||
request,
|
||||
forceNotNull: false,
|
||||
excludes: new List<XUserSelectBy> {
|
||||
XUserSelectBy.ID,
|
||||
XUserSelectBy.Email,
|
||||
XUserSelectBy.MobileNumber
|
||||
});
|
||||
|
||||
//
|
||||
// if it's null, means user doesn't have Invitation Token
|
||||
// and there is no User Selector ...
|
||||
if (userSelectByParam.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
// Since Email is Unique so it can act as a
|
||||
// UserSelector ...
|
||||
userSelectByParam = emailAddress;
|
||||
}
|
||||
|
||||
//
|
||||
// Define empty Verification Code
|
||||
// and Empty Verification Request ...
|
||||
var verificationCode = "";
|
||||
XVerificationRequest xVerificationRequest = null;
|
||||
|
||||
//
|
||||
// Check Device Request Verification Code before or Not ...
|
||||
var isDeviceRequested = await IsDeviceRequestedForVerificationCodeBefor(device);
|
||||
if (isDeviceRequested)
|
||||
{
|
||||
//
|
||||
// if Requested before, Retrieve XVerification instance by Device from Db
|
||||
// and Validate it ...
|
||||
xVerificationRequest = await ValidateAndRetrieveVerificationRequest(device);
|
||||
|
||||
//
|
||||
if (xVerificationRequest.VerificationCode.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
verificationCode = GenerateRandom().ToString();
|
||||
xVerificationRequest.VerificationCode = verificationCode;
|
||||
|
||||
//
|
||||
await RemoveVerificationCodeRequestByDevice(
|
||||
device,
|
||||
saveChanges: false
|
||||
);
|
||||
await AddVerificationRequest(
|
||||
xVerificationRequest,
|
||||
saveChanges: true
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// if XVerificationRequest is Valid, it must Contain an Alive Verification Code
|
||||
// so retrieve it and assign it ...
|
||||
verificationCode = xVerificationRequest.VerificationCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
verificationCode = GenerateRandom().ToString();
|
||||
}
|
||||
|
||||
//
|
||||
// Check Context Email and given Email ...
|
||||
if (!request.Context.Email.IsNullOrEmpty() &&
|
||||
emailAddress != request.Context.Email)
|
||||
{
|
||||
XException.InvalidEmailAddress.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Check User Added To Db or Not ...
|
||||
var isAddedUser = !request.Context.UserId.IsNullOrEmpty();
|
||||
if (isAddedUser)
|
||||
{
|
||||
//
|
||||
// Validate User Exists and Retireve User Object ...
|
||||
var user = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
containDetails: false,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false);
|
||||
|
||||
//
|
||||
// Check Email Same ...
|
||||
if (user.Email == emailAddress &&
|
||||
user.EmailConfirmed)
|
||||
{
|
||||
XException.MobilesSame.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Update User Object's Email and
|
||||
// Confirmation Status ...
|
||||
user.Email = emailAddress;
|
||||
user.EmailConfirmed = false;
|
||||
|
||||
//
|
||||
// Save Changes to Db ...
|
||||
await UpdateUserAsync(
|
||||
user,
|
||||
checkCanLoginPolicies: false,
|
||||
checkIsBanned: false
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare Verification Request by Checking Next Tries,
|
||||
// Device Status, and etc, Update or Add XVerificationRequest to db
|
||||
// and Retrieve the added Entity ...
|
||||
xVerificationRequest = await HandleVerificationRequestPreparation(verificationCode, request);
|
||||
|
||||
//
|
||||
// Update Request Context Email
|
||||
// and it's Confirmation Status ...
|
||||
request.Context.Email = emailAddress;
|
||||
request.Context.EmailVerified = false;
|
||||
|
||||
//
|
||||
// Prepare New Token Result Resource,
|
||||
// by Requesting an Action ...
|
||||
var result = await ActionRequest(
|
||||
lang,
|
||||
device,
|
||||
userSelectByParam,
|
||||
XAction.RequestEmailVerificationCode,
|
||||
request.Context,
|
||||
forceCheckUserExists: isAddedUser
|
||||
);
|
||||
|
||||
//
|
||||
// Remove Hash ...
|
||||
await RemoveTokenByHash(actionToken);
|
||||
|
||||
//
|
||||
// Prepare Message ...
|
||||
var xMessage = GetVerificationCodeMessage(lang, emailAddress, verificationCode);
|
||||
|
||||
//
|
||||
// Send Verification Code Message to User Using Mail Provider ...
|
||||
await MessageProvider.SendMailAsync(xMessage, throwException: false);
|
||||
|
||||
//
|
||||
// Return Result ...
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Role Actions ...
|
||||
/// <summary>
|
||||
/// Check a Role exists or not
|
||||
/// </summary>
|
||||
/// <param name="roleName">role name</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public async Task<bool> IsRoleExistsAsync(
|
||||
string roleName
|
||||
)
|
||||
{
|
||||
//
|
||||
if (roleName.IsNullOrEmpty())
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
return await RoleManager.RoleExistsAsync(roleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new Role
|
||||
/// </summary>
|
||||
/// <param name="roleName">role name</param>
|
||||
/// <returns>an instance of <see>IdentityResult</see></returns>
|
||||
public async Task<IdentityResult> CreateRoleAsync(
|
||||
string roleName
|
||||
)
|
||||
{
|
||||
//
|
||||
var isExists = await RoleManager
|
||||
.RoleExistsAsync(roleName);
|
||||
if (isExists)
|
||||
{
|
||||
XException.Duplicate.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var result = await RoleManager
|
||||
.CreateAsync(new IdentityRole(roleName));
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a Role
|
||||
/// </summary>
|
||||
/// <param name="roleName">role name</param>
|
||||
/// <returns>an instance of <see>IdentityRole</see></returns>
|
||||
public async Task<IdentityRole> GetRoleAsync(
|
||||
string roleName
|
||||
)
|
||||
{
|
||||
//
|
||||
var isExists = await IsRoleExistsAsync(roleName);
|
||||
if (!isExists)
|
||||
{
|
||||
XException.NotFound.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var result = await RoleManager
|
||||
.FindByNameAsync(roleName);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a User From Role
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <param name="roleName">role name</param>
|
||||
/// <returns>an instance of <see>IdentityResult</see></returns>
|
||||
public async Task<IdentityResult> RemoveFromRoleAsync(
|
||||
XUser user,
|
||||
string roleName
|
||||
)
|
||||
{
|
||||
return await UserManager.RemoveFromRoleAsync(user, roleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a User From Roles
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <param name="roleNames">a collection of role names</param>
|
||||
/// <returns>an instance of <see>IdentityResult</see></returns>
|
||||
public async Task<IdentityResult> RemoveFromRolesAsync(
|
||||
XUser user,
|
||||
IEnumerable<string> roleNames
|
||||
)
|
||||
{
|
||||
return await UserManager.RemoveFromRolesAsync(user, roleNames);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assign a User to Specific Role
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <param name="roleName">role name</param>
|
||||
/// <returns>an instance of <see>IdentityResult</see></returns>
|
||||
public async Task<IdentityResult> AddUserToRoleAsync(
|
||||
XUser user,
|
||||
string roleName
|
||||
)
|
||||
{
|
||||
//
|
||||
if (user == null ||
|
||||
roleName.IsNullOrEmpty())
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var userSelectByParam = GetUserSelectByParam(user);
|
||||
var isExistsUser = await IsUserExistsAsync(userSelectByParam);
|
||||
var isExistsRole = await IsRoleExistsAsync(roleName);
|
||||
if (!isExistsUser || !isExistsRole)
|
||||
{
|
||||
XException.NotFound.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var result = await UserManager
|
||||
.AddToRoleAsync(user, roleName);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Role Name by it's ID
|
||||
/// </summary>
|
||||
/// <param name="roleId">role id</param>
|
||||
/// <returns>role name as string</returns>
|
||||
public async Task<string> GetRoleNameAsync(
|
||||
string roleId
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (roleId.IsNullOrEmpty())
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var role = await RoleManager
|
||||
.FindByIdAsync(roleId);
|
||||
|
||||
//
|
||||
return role.Name.ToNormalString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a List Of User Roles
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">user identifier</param>
|
||||
/// <param name="checkCanLoginPolicies"></param>
|
||||
/// <param name="checkIsBanned"></param>
|
||||
/// <returns>a collection of role names</returns>
|
||||
public async Task<IEnumerable<string>> GetRoleNamesAsync(
|
||||
string userSelectByParam,
|
||||
bool checkCanLoginPolicies = true,
|
||||
bool checkIsBanned = true
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (userSelectByParam.IsNullOrEmpty())
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var user = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
containDetails: true,
|
||||
checkCanLoginPolicies: checkCanLoginPolicies,
|
||||
checkIsBanned: checkIsBanned
|
||||
);
|
||||
|
||||
//
|
||||
var result = new List<string>();
|
||||
foreach (var role in user.Roles)
|
||||
{
|
||||
//
|
||||
var roleName = await GetRoleNameAsync(role.RoleId);
|
||||
roleName = roleName.ToNormalString();
|
||||
|
||||
//
|
||||
result.Add(roleName);
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a User is Adminr not
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">user identifier</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public async Task<bool> IsAdmin(
|
||||
string userSelectByParam
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
|
||||
//
|
||||
var user = await ValidateUserExistsAndRetrieve(
|
||||
userSelectByParam,
|
||||
containDetails: true,
|
||||
checkCanLoginPolicies: true);
|
||||
|
||||
//
|
||||
var result = await IsAdmin(user);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a User is Adminr not
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
public async Task<bool> IsAdmin(
|
||||
XUser user
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotNull(user);
|
||||
ValidationProvider.NotEmpty(user.Id);
|
||||
|
||||
//
|
||||
// Retrieve Admin Role ...
|
||||
// TODO: Fix this ...
|
||||
var adminRole = "admin";
|
||||
// XUserRole.Admin
|
||||
// .GetStringValue ()
|
||||
// .ToNormalString ();
|
||||
|
||||
//
|
||||
// Check Admin Role Exists in User Roles or not ...
|
||||
var userRoleNames = await GetRoleNamesAsync(user.Id);
|
||||
var isContainsAdminRole = userRoleNames.Contains(adminRole);
|
||||
|
||||
//
|
||||
// Return Result ...
|
||||
return isContainsAdminRole;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
using System.Threading.Tasks;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels.Dtos;
|
||||
using xModels.Dtos;
|
||||
using xDataService.Extensions;
|
||||
using xIds.Extensions;
|
||||
using System.Linq;
|
||||
using xIdentityModels.Extensions;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Actions ...
|
||||
/// <summary>
|
||||
/// Query User Profiles
|
||||
/// </summary>
|
||||
/// <param name="requestedUserSelectByParam">requested user's identifier</param>
|
||||
/// <param name="query">how to filter results based on <see>XQuery</see> structure</param>
|
||||
/// <returns>an instance of <see>XQueryResult</see> of <see>XUserProfileDto</see></returns>
|
||||
public async Task<XQueryResult<XUserProfileDto>> QueryOpenToSearchUsers(
|
||||
string requestedUserSelectByParam,
|
||||
XQuery query
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validation ...
|
||||
if (query.IsNull())
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Normalize ...
|
||||
query = query.NormalizeQuery(DataConfiguration.ToXDataServiceConfig());
|
||||
|
||||
//
|
||||
// Since in Resourceable Entities we have to Search on Locales
|
||||
// we Must Implement Senario Custom ...
|
||||
var totalEntities = GetUsersDbSet()
|
||||
.Where(u => u.OpenToSearch)
|
||||
.ToList()
|
||||
.Where(u => !u.ContainsUserSelectByParam(requestedUserSelectByParam))
|
||||
.Select(u => u.Id)
|
||||
.ToList();
|
||||
|
||||
//
|
||||
var items = await GetUserProfilesAsync(
|
||||
totalEntities,
|
||||
requestedUserSelectByParam,
|
||||
checkIsBanned: false,
|
||||
checkCanLoginPolicies: false,
|
||||
forceCheckRequestedUser: false
|
||||
);
|
||||
|
||||
//
|
||||
var totalItemsCount = items.Count();
|
||||
|
||||
//
|
||||
// Apply Filter ...
|
||||
if (!query.Filter.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
items = items
|
||||
.ApplyFilter(query.Filter);
|
||||
}
|
||||
int filteredItemsCount = items.Count();
|
||||
|
||||
//
|
||||
// Count Pages ...
|
||||
var totalPagesCount = query.CountPages(totalItemsCount);
|
||||
var filteredPagesCount = query.CountPages(filteredItemsCount);
|
||||
|
||||
//
|
||||
// Apply Paging and Sorting ...
|
||||
if (totalItemsCount > 0 &&
|
||||
filteredItemsCount > 0)
|
||||
{
|
||||
//
|
||||
// Apply Sorting ...
|
||||
items = items
|
||||
.ToList()
|
||||
.ApplySorting(
|
||||
query.SortBy,
|
||||
query.IsAscending
|
||||
);
|
||||
|
||||
//
|
||||
// Apply Paging ...
|
||||
items = items
|
||||
.ToList()
|
||||
.ApplyPaging(
|
||||
query.Page,
|
||||
query.PageSize
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Generate Result Object ...
|
||||
// Query = query,
|
||||
var result = new XQueryResult<XUserProfileDto>
|
||||
{
|
||||
Items = items,
|
||||
Page = query.Page,
|
||||
PageSize = query.PageSize,
|
||||
TotalPages = totalPagesCount,
|
||||
TotalItems = totalItemsCount,
|
||||
TotalFilteredPages = filteredPagesCount,
|
||||
TotalFilteredItems = filteredItemsCount
|
||||
};
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels.Descriptors;
|
||||
using xIdentityModels.Extensions;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Default Identity Preparation Actions ...
|
||||
/// <summary>
|
||||
/// Create Default Roles based on Identity Configuration
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task CreateIdentityRoles()
|
||||
{
|
||||
//
|
||||
if (Configuration == null ||
|
||||
Configuration.IdentityRoles == null ||
|
||||
Configuration.IdentityRoles.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Check New Users Role exists in IdentityRole or not ...
|
||||
if (!Configuration.NewUsersRole.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
// Ensure NewUsersRole Exists in IdentityRoles ...
|
||||
var isNewUserRoleExistsInIdentityRoles = Configuration
|
||||
.IdentityRoles
|
||||
.Contains(Configuration.NewUsersRole);
|
||||
if (!isNewUserRoleExistsInIdentityRoles)
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// loop through all roles and create them one by one ...
|
||||
foreach (var roleName in Configuration.IdentityRoles)
|
||||
{
|
||||
//
|
||||
var isRoleExists = await RoleManager.RoleExistsAsync(roleName);
|
||||
if (!isRoleExists)
|
||||
{
|
||||
//
|
||||
var result = await RoleManager.CreateAsync(new IdentityRole(roleName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a user Based on User Descriptor
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XIdentityUserDescriptor</see></param>
|
||||
/// <returns></returns>
|
||||
public async Task CreateUserAsync(
|
||||
XIdentityUserDescriptor user
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotNull(user);
|
||||
|
||||
//
|
||||
var isExistsRole = await RoleManager.RoleExistsAsync(user.Role);
|
||||
if (!isExistsRole)
|
||||
{
|
||||
//
|
||||
// Check Assigned role to user exists in app roles ...
|
||||
if (!Configuration
|
||||
.IdentityRoles
|
||||
.Contains(user.Role))
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Ensure All Roles Created ...
|
||||
await CreateIdentityRoles();
|
||||
}
|
||||
|
||||
//
|
||||
// Check User Exists ...
|
||||
var isExistsUser = await IsUserExistsAsync(user.UserName);
|
||||
if (!isExistsUser)
|
||||
{
|
||||
//
|
||||
// Create a DashboardUser instance based on Configuration Data ...
|
||||
var userEntity = user.ToXUser();
|
||||
|
||||
//
|
||||
// Try to Create User ...
|
||||
var userCreateResult = await CreateUserAsync(
|
||||
userEntity,
|
||||
user.Password
|
||||
);
|
||||
if (!userCreateResult.Succeeded)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Assign Admin User to it's Role ...
|
||||
var roleAssignResult = await UserManager.AddToRoleAsync(userEntity, user.Role);
|
||||
if (!roleAssignResult.Succeeded)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
var claims = await ToJwtClaims(
|
||||
userEntity,
|
||||
checkCanLoginPolicies: true,
|
||||
checkIsBanned: true);
|
||||
|
||||
//
|
||||
var addClaimsResult = await UserManager.AddClaimsAsync(userEntity, claims);
|
||||
if (!addClaimsResult.Succeeded)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,742 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using xCommons.Extensions;
|
||||
using xCommons.Helpers;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels;
|
||||
using xIdentityModels.Constants;
|
||||
using xIdentityModels.Extensions;
|
||||
using xIdentityModels.Models;
|
||||
using xIdentityModels.Navigations;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Token Actions ...
|
||||
/// <summary>
|
||||
/// Check a Token Entity Exists or not
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="type">specifies Action Step by a member of <see>XAction</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
private async Task<bool> IsTokenExistsByDeviceAndType(
|
||||
XDevice device,
|
||||
XAction type
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotNull(device);
|
||||
|
||||
//
|
||||
var isExists = false;
|
||||
var enumerator = DbContext.Tokens.AsAsyncEnumerable();
|
||||
await
|
||||
foreach (var token in enumerator)
|
||||
{
|
||||
//
|
||||
if (token.Type == type &&
|
||||
token.Device.IsSameAs(device))
|
||||
{
|
||||
isExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return isExists;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a Token Entity Exists or not
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">specified user's identifier</param>
|
||||
/// <param name="type">specifies Action Step by a member of <see>XAction</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
private async Task<bool> IsTokenExistsByUserAndType(
|
||||
string userSelectByParam,
|
||||
XAction type
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
|
||||
//
|
||||
var isExists = false;
|
||||
var tokensEnumerator = DbContext.Tokens.AsAsyncEnumerable();
|
||||
await
|
||||
foreach (var token in tokensEnumerator)
|
||||
{
|
||||
//
|
||||
if (token.Type == type &&
|
||||
token.UserSelectByParam
|
||||
.ToNormalString() == userSelectByParam
|
||||
.ToNormalString())
|
||||
{
|
||||
//
|
||||
isExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return isExists;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a Token Entity Exists or not
|
||||
/// </summary>
|
||||
/// <param name="token">represent specified action token</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
private async Task<bool> IsTokenExistsByToken(
|
||||
string token
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = await DbContext.Tokens
|
||||
.AnyAsync(xt => xt.Token == token);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a Token Entity Exists or not
|
||||
/// </summary>
|
||||
/// <param name="hash">represent specified action token hash</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
private async Task<bool> IsTokenExistsByHash(
|
||||
string hash
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = await DbContext.Tokens
|
||||
.AnyAsync(xt => xt.Hash == hash);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a Token Entity Exists or not
|
||||
/// </summary>
|
||||
/// <param name="item">an instance of <see>XToken</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
private async Task<bool> IsTokenExistsByToken(
|
||||
XToken item
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = false;
|
||||
var tokenEnumerator = DbContext.Tokens
|
||||
.AsAsyncEnumerable();
|
||||
await
|
||||
foreach (var token in tokenEnumerator)
|
||||
{
|
||||
//
|
||||
if (token.Hash == item.Hash &&
|
||||
token.Token == item.Token &&
|
||||
token.Type == item.Type &&
|
||||
token.UserSelectByParam
|
||||
.ToNormalString() == item.UserSelectByParam
|
||||
.ToNormalString() &&
|
||||
token.Device.IsSameAs(item.Device))
|
||||
{
|
||||
//
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a Token Entity Exists or not
|
||||
/// </summary>
|
||||
/// <param name="id">specifies token id</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
private async Task<bool> IsTokenExistsById(
|
||||
int id
|
||||
)
|
||||
{
|
||||
return await DbContext.Tokens.AnyAsync(t => t.Id == id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Token Entity
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="type">specifies Action Step by a member of <see>XAction</see></param>
|
||||
/// <returns>an instance of <see>XToken</see></returns>
|
||||
private async Task<XToken> GetTokenByDeviceAndType(
|
||||
XDevice device,
|
||||
XAction type
|
||||
)
|
||||
{
|
||||
//
|
||||
var isExists = await IsTokenExistsByDeviceAndType(device, type);
|
||||
if (!isExists)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
XToken item = null;
|
||||
var enumerator = DbContext.Tokens.AsAsyncEnumerable();
|
||||
await
|
||||
foreach (var token in enumerator)
|
||||
{
|
||||
//
|
||||
if (token.Type == type &&
|
||||
token.Device.IsSameAs(device))
|
||||
{
|
||||
//
|
||||
item = token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Token Entity
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">specified user's identifier</param>
|
||||
/// <param name="type">specifies Action Step by a member of <see>XAction</see></param>
|
||||
/// <returns>an instance of <see>XToken</see></returns>
|
||||
private async Task<XToken> GetTokenByUserAndType(
|
||||
string userSelectByParam,
|
||||
XAction type
|
||||
)
|
||||
{
|
||||
//
|
||||
var isExists = await IsTokenExistsByUserAndType(userSelectByParam, type);
|
||||
if (!isExists)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
XToken item = null;
|
||||
var enumerator = DbContext.Tokens.AsAsyncEnumerable();
|
||||
await
|
||||
foreach (var token in enumerator)
|
||||
{
|
||||
//
|
||||
if (token.Type == type &&
|
||||
token.UserSelectByParam
|
||||
.ToNormalString() == userSelectByParam
|
||||
.ToNormalString())
|
||||
{
|
||||
//
|
||||
item = token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a Token Entity
|
||||
/// </summary>
|
||||
/// <param name="token">represent specified action token</param>
|
||||
/// <returns>an instance of <see>XToken</see></returns>
|
||||
private async Task<XToken> GetTokenByToken(
|
||||
string token
|
||||
)
|
||||
{
|
||||
//
|
||||
var isExists = await IsTokenExistsByToken(token);
|
||||
if (!isExists)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
var result = await DbContext.Tokens
|
||||
.FirstOrDefaultAsync(xt => xt.Token == token);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Related Hash to a Token
|
||||
/// </summary>
|
||||
/// <param name="token">represent specified action token</param>
|
||||
/// <returns>hash string</returns>
|
||||
private async Task<string> GetRelatedHashByToken(
|
||||
string token
|
||||
)
|
||||
{
|
||||
//
|
||||
var item = await GetTokenByToken(token);
|
||||
if (item == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
return item.Hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a Token Entity
|
||||
/// </summary>
|
||||
/// <param name="hash">represent specified action token hash</param>
|
||||
/// <returns>an instance of <see>XToken</see></returns>
|
||||
private async Task<XToken> GetTokenByHash(
|
||||
string hash
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(hash);
|
||||
|
||||
//
|
||||
var isExists = await IsTokenExistsByHash(hash);
|
||||
if (!isExists)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
var item = await DbContext.Tokens
|
||||
.FirstOrDefaultAsync(t => t.Hash == hash);
|
||||
|
||||
//
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Related Token to a Hash string
|
||||
/// </summary>
|
||||
/// <param name="hash">represent specified action token hash</param>
|
||||
/// <returns>token string</returns>
|
||||
private async Task<string> GetRelatedTokenByHash(
|
||||
string hash
|
||||
)
|
||||
{
|
||||
//
|
||||
var item = await GetTokenByHash(hash);
|
||||
if (item == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
return item.Token;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a Token Expiration Date
|
||||
/// </summary>
|
||||
/// <param name="token">represent specified action token</param>
|
||||
/// <returns>an instance of <see>DateTime</see></returns>
|
||||
private DateTime GetTokenExpirationDate(
|
||||
string token
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotEmpty(token);
|
||||
|
||||
//
|
||||
var result = IdentityHelper.GetTokenExpirationDate(token);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a Token Entity
|
||||
/// </summary>
|
||||
/// <param name="token">represent specified action token</param>
|
||||
/// <returns></returns>
|
||||
private async Task RemoveTokenByToken(
|
||||
string token
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(token);
|
||||
|
||||
//
|
||||
var isExists = await IsTokenExistsByToken(token);
|
||||
if (!isExists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
var item = await GetTokenByToken(token);
|
||||
if (item == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
DbContext.Tokens.Remove(item);
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a Token Entity
|
||||
/// </summary>
|
||||
/// <param name="hash">represent specified action token hash</param>
|
||||
/// <returns></returns>
|
||||
private async Task RemoveTokenByHash(
|
||||
string hash
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(hash);
|
||||
|
||||
//
|
||||
var isExists = await IsTokenExistsByHash(hash);
|
||||
if (!isExists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
var item = await GetTokenByHash(hash);
|
||||
if (item == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
DbContext.Tokens.Remove(item);
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a Token Entity
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns></returns>
|
||||
private async Task RemoveTokenByDevice(
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotNull(device);
|
||||
|
||||
//
|
||||
XToken items = null;
|
||||
var enumerator = DbContext.Tokens.AsAsyncEnumerable();
|
||||
await
|
||||
foreach (var token in enumerator)
|
||||
{
|
||||
//
|
||||
if (token.Device.IsSameAs(device))
|
||||
{
|
||||
//
|
||||
items = token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
if (!items.IsNull())
|
||||
{
|
||||
DbContext.Tokens.RemoveRange(items);
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// add a token Entity
|
||||
/// </summary>
|
||||
/// <param name="item">an instance of <see>XToken</see></param>
|
||||
/// <returns>an instance of <see>XToken</see></returns>
|
||||
private async Task<XToken> AddTokenAsync(
|
||||
XToken item
|
||||
)
|
||||
{
|
||||
//
|
||||
var isExist = await IsTokenExistsByToken(item);
|
||||
if (isExist)
|
||||
{
|
||||
return await GetTokenByHash(item.Hash);
|
||||
}
|
||||
|
||||
//
|
||||
var entry = await DbContext.Tokens.AddAsync(item);
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
||||
//
|
||||
return entry.Entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hash a Request Token
|
||||
/// </summary>
|
||||
/// <param name="request">an instance of <see>XActionRequestToken</see></param>
|
||||
/// <param name="forceNotNullUserSelectByParam"></param>
|
||||
/// <param name="forceDeviceNotNull"></param>
|
||||
/// <returns>an instance of <see>XToken</see></returns>
|
||||
private async Task<XToken> HashRequest(
|
||||
XActionRequestToken request,
|
||||
bool forceNotNullUserSelectByParam = true,
|
||||
bool forceDeviceNotNull = true
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
var secretKey = Configuration.IdentitySecretKey;
|
||||
ValidationProvider.NotNull(request);
|
||||
ValidationProvider.NotEmpty(secretKey);
|
||||
|
||||
//
|
||||
ValidateActionRequest(request);
|
||||
|
||||
//
|
||||
var type = request.Action;
|
||||
var device = request.Context.Device;
|
||||
var tokenObject = ToSecurityToken(request);
|
||||
var tokenString = ToTokenString(tokenObject);
|
||||
var tokenHash = ToHash(tokenString);
|
||||
var userSelectByParam = GetUserSelectByParam(request, forceNotNullUserSelectByParam);
|
||||
|
||||
//
|
||||
if (forceNotNullUserSelectByParam)
|
||||
{
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
}
|
||||
|
||||
//
|
||||
ValidationProvider.NotEmpty(tokenString, tokenHash);
|
||||
|
||||
//
|
||||
if (forceDeviceNotNull)
|
||||
{
|
||||
ValidationProvider.NotNull(device);
|
||||
}
|
||||
|
||||
//
|
||||
ValidationProvider.NotNull(tokenObject);
|
||||
|
||||
//
|
||||
var xToken = new XToken
|
||||
{
|
||||
Type = type,
|
||||
Device = device,
|
||||
Hash = tokenHash,
|
||||
Token = tokenString,
|
||||
UserSelectByParam = userSelectByParam
|
||||
};
|
||||
|
||||
//
|
||||
var addedToken = await AddTokenAsync(xToken);
|
||||
|
||||
//
|
||||
return addedToken;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate Token Hash string
|
||||
/// </summary>
|
||||
/// <param name="token">represent specified action token</param>
|
||||
/// <param name="checkValidation">check token validation parameters, default is true</param>
|
||||
/// <returns>hash string</returns>
|
||||
private string ToHash(
|
||||
string token,
|
||||
bool checkValidation = true
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotEmpty(token);
|
||||
|
||||
//
|
||||
if (checkValidation)
|
||||
{
|
||||
ValidateToken(token);
|
||||
}
|
||||
|
||||
//
|
||||
var result = token.ToMd5String().ToNormalString();
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate Token string
|
||||
/// </summary>
|
||||
/// <param name="token">represent specified action token</param>
|
||||
/// <returns>token string</returns>
|
||||
private string ToTokenString(
|
||||
SecurityToken token
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotNull(token, IdentityHelper);
|
||||
|
||||
//
|
||||
var result = IdentityHelper.ToTokenString(token);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate Token string
|
||||
/// </summary>
|
||||
/// <param name="token">represent specified action token</param>
|
||||
/// <returns>token string</returns>
|
||||
private string ToTokenString(
|
||||
JwtSecurityToken token
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotNull(token, IdentityHelper);
|
||||
|
||||
//
|
||||
var result = IdentityHelper.ToTokenString(token);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate Security Token
|
||||
/// </summary>
|
||||
/// <param name="token">represent specified action token</param>
|
||||
/// <returns>an instance of <see>SecurityToken</see></returns>
|
||||
private SecurityToken ToSecurityToken(
|
||||
string token
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotEmpty(token);
|
||||
|
||||
//
|
||||
var result = IdentityHelper.ToSecurityToken(token);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate Security Token
|
||||
/// </summary>
|
||||
/// <param name="request">an instance of <see>XActionRequestToken</see></param>
|
||||
/// <returns>an instance of <see>SecurityToken</see></returns>
|
||||
private SecurityToken ToSecurityToken(
|
||||
XActionRequestToken request
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotNull(request);
|
||||
|
||||
//
|
||||
ValidateActionRequest(request);
|
||||
|
||||
//
|
||||
var result = IdentityHelper.ToSecurityToken(request);
|
||||
if (result == null)
|
||||
{
|
||||
XException.InvalidToken.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup all exists tokens related to specified User
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParam">specified user's identifier</param>
|
||||
/// <returns></returns>
|
||||
private async Task HandleRemoveExistsTokens(
|
||||
string userSelectByParam
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
ValidationProvider.NotEmpty(userSelectByParam);
|
||||
|
||||
//
|
||||
var xTokens = new List<XToken>();
|
||||
var xTokenEnumerator = DbContext.Tokens.AsAsyncEnumerable();
|
||||
await
|
||||
foreach (var xToken in xTokenEnumerator)
|
||||
{
|
||||
//
|
||||
if (xToken.UserSelectByParam == userSelectByParam &&
|
||||
ObjectHelper.ToEnumerableValues<XAction>().Contains(xToken.Type))
|
||||
{
|
||||
xTokens.Add(xToken);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
if (xTokens.HasChild())
|
||||
{
|
||||
DbContext.Tokens.RemoveRange(xTokens);
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup all tokens related to specified User
|
||||
/// </summary>
|
||||
/// <param name="userSelectByParams">a collection of user identifiers</param>
|
||||
/// <returns></returns>
|
||||
private async Task HandleCleanUserTokens(
|
||||
ICollection<string> userSelectByParams
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (!userSelectByParams.HasChild())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
foreach (var userSelectByParam in userSelectByParams)
|
||||
{
|
||||
await HandleRemoveExistsTokens(userSelectByParam);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup all tokens related to specified User
|
||||
/// </summary>
|
||||
/// <param name="user">an instance of <see>XUser</see></param>
|
||||
/// <returns></returns>
|
||||
private async Task HandleCleanUserTokens(
|
||||
XUser user
|
||||
)
|
||||
{
|
||||
//
|
||||
if (user == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
var userSelectByParams = GenerateUserSelectByParams(user);
|
||||
|
||||
//
|
||||
await HandleCleanUserTokens(userSelectByParams);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,220 @@
|
||||
using System.Threading.Tasks;
|
||||
using xCommons.Extensions;
|
||||
using xIdentityModels.Extensions;
|
||||
using xIdentityModels.Models;
|
||||
using xIdentityModels.Navigations;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public partial class XIdentityManager
|
||||
{
|
||||
//
|
||||
#region Verification Code Actions ...
|
||||
/// <summary>
|
||||
/// Check a Device Requeste for Verification Code before or not
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns>a boolean value</returns>
|
||||
private async Task<bool> IsDeviceRequestedForVerificationCodeBefor(
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
//
|
||||
var result = false;
|
||||
var enumerator = DbContext.VerificationRequests
|
||||
.AsAsyncEnumerable();
|
||||
await
|
||||
foreach (var entity in enumerator)
|
||||
{
|
||||
//
|
||||
if (entity.Device.IsSameAs(device))
|
||||
{
|
||||
//
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a Verification Code Requested before or not
|
||||
/// </summary>
|
||||
/// <param name="verificationCode">Confirm Verification Code</param>
|
||||
/// <returns>a boolean value</returns>
|
||||
private async Task<bool> IsVerificationCodeRequested(
|
||||
string verificationCode
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (verificationCode.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
var result = false;
|
||||
var enumerator = DbContext.VerificationRequests
|
||||
.AsAsyncEnumerable();
|
||||
await
|
||||
foreach (var entity in enumerator)
|
||||
{
|
||||
//
|
||||
if (entity.VerificationCode == verificationCode)
|
||||
{
|
||||
//
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Verification Request
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <returns>an instance of <see>XVerificationRequest</see></returns>
|
||||
private async Task<XVerificationRequest> GetVerificationRequest(
|
||||
XDevice device
|
||||
)
|
||||
{
|
||||
//
|
||||
XVerificationRequest result = null;
|
||||
var enumerator = DbContext.VerificationRequests
|
||||
.AsAsyncEnumerable();
|
||||
await
|
||||
foreach (var entity in enumerator)
|
||||
{
|
||||
//
|
||||
if (entity.Device.IsSameAs(device))
|
||||
{
|
||||
//
|
||||
result = entity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Verification Request
|
||||
/// </summary>
|
||||
/// <param name="verificationCode">Confirm Verification Code</param>
|
||||
/// <returns>an instance of <see>XVerificationRequest</see></returns>
|
||||
private async Task<XVerificationRequest> GetVerificationRequest(
|
||||
string verificationCode
|
||||
)
|
||||
{
|
||||
//
|
||||
XVerificationRequest result = null;
|
||||
var enumerator = DbContext.VerificationRequests
|
||||
.AsAsyncEnumerable();
|
||||
await
|
||||
foreach (var entity in enumerator)
|
||||
{
|
||||
//
|
||||
if (entity.VerificationCode == verificationCode)
|
||||
{
|
||||
//
|
||||
result = entity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove Exists Verification Code Request
|
||||
/// </summary>
|
||||
/// <param name="device">an instance of <see>XDevice</see></param>
|
||||
/// <param name="saveChanges">save changes on DbContext, default is true</param>
|
||||
/// <returns></returns>
|
||||
private async Task RemoveVerificationCodeRequestByDevice(
|
||||
XDevice device,
|
||||
bool saveChanges = true
|
||||
)
|
||||
{
|
||||
//
|
||||
if (!await IsDeviceRequestedForVerificationCodeBefor(device))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
var xvr = await GetVerificationRequest(device);
|
||||
DbContext.VerificationRequests.Remove(xvr);
|
||||
|
||||
//
|
||||
if (saveChanges)
|
||||
{
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove Exists Verification Code Request
|
||||
/// </summary>
|
||||
/// <param name="verificationCode">Confirm Verification Code</param>
|
||||
/// <param name="saveChanges">save changes on DbContext, default is true</param>
|
||||
/// <returns></returns>
|
||||
private async Task RemoveVerificationRequest(
|
||||
string verificationCode,
|
||||
bool saveChanges = true
|
||||
)
|
||||
{
|
||||
//
|
||||
ValidationProvider.NotEmpty(verificationCode);
|
||||
|
||||
//
|
||||
var request = await GetVerificationRequest(verificationCode);
|
||||
DbContext.VerificationRequests.Remove(request);
|
||||
|
||||
//
|
||||
if (saveChanges)
|
||||
{
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add Verification Code Request
|
||||
/// </summary>
|
||||
/// <param name="request">an instance of <see>XVerificationRequest</see></param>
|
||||
/// <param name="saveChanges">save changes on DbContext, default is true</param>
|
||||
/// <returns>an instance of <see>XVerificationRequest</see></returns>
|
||||
private async Task<XVerificationRequest> AddVerificationRequest(
|
||||
XVerificationRequest request,
|
||||
bool saveChanges = true
|
||||
)
|
||||
{
|
||||
//
|
||||
if (await IsDeviceRequestedForVerificationCodeBefor(request.Device))
|
||||
{
|
||||
await RemoveVerificationCodeRequestByDevice(request.Device);
|
||||
}
|
||||
|
||||
//
|
||||
var entry = await DbContext.VerificationRequests.AddAsync(request);
|
||||
|
||||
//
|
||||
if (saveChanges)
|
||||
{
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
//
|
||||
return entry.Entity;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels.Configurations;
|
||||
using xIds.Constants;
|
||||
using xIds.Interfaces;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public class XIdentityMessageProvider : IXIdentityMessageProvider
|
||||
{
|
||||
//
|
||||
public string InviteMsg { get; set; }
|
||||
public string RegistrationApproveMsg { get; set; }
|
||||
public string RegisteredMsg { get; set; }
|
||||
public string VerificationCodeMsg { get; set; }
|
||||
public string ChangePasswordMsg { get; set; }
|
||||
public string PasswordChangedMsg { get; set; }
|
||||
public string NewDeviceLoggedInMsg { get; set; }
|
||||
|
||||
private readonly ILogger<IXIdentityMessageProvider> logger;
|
||||
private readonly XIdentityConfiguration identityConfiguration;
|
||||
|
||||
public XIdentityMessageProvider(
|
||||
ILogger<IXIdentityMessageProvider> logger,
|
||||
XIdentityConfiguration identityConfiguration
|
||||
)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.identityConfiguration = identityConfiguration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine All things is Ready or Not
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsReady()
|
||||
{
|
||||
return !InviteMsg.IsNullOrEmpty() &&
|
||||
!RegistrationApproveMsg.IsNullOrEmpty() &&
|
||||
!RegisteredMsg.IsNullOrEmpty() &&
|
||||
!VerificationCodeMsg.IsNullOrEmpty() &&
|
||||
!ChangePasswordMsg.IsNullOrEmpty() &&
|
||||
!PasswordChangedMsg.IsNullOrEmpty() &&
|
||||
!NewDeviceLoggedInMsg.IsNullOrEmpty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a Translated Value Based on Given Lang
|
||||
/// </summary>
|
||||
/// <param name="resourceTitle"></param>
|
||||
/// <param name="lang"></param>
|
||||
/// <returns></returns>
|
||||
private string GetStringResource(string resourceTitle, string lang)
|
||||
{
|
||||
//
|
||||
var item = identityConfiguration.IdentityMessages
|
||||
.FirstOrDefault(sr =>
|
||||
sr.Language.ToNormalString() == lang.ToNormalString() &&
|
||||
sr.ResourceTitle.ToNormalString() == resourceTitle.ToNormalString());
|
||||
//
|
||||
if (item == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
return item.TranslatedValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepare Helper Class and Fill Messages
|
||||
/// with Specific Language
|
||||
/// </summary>
|
||||
/// <param name="lang"></param>
|
||||
public void PrepareMessages(string lang)
|
||||
{
|
||||
//
|
||||
InviteMsg = GetStringResource(IdentityMessagesKeys.InviteMsg, lang);
|
||||
RegisteredMsg = GetStringResource(IdentityMessagesKeys.RegisteredMsg, lang);
|
||||
ChangePasswordMsg = GetStringResource(IdentityMessagesKeys.ChangePasswordMsg, lang);
|
||||
PasswordChangedMsg = GetStringResource(IdentityMessagesKeys.PasswordChangedMsg, lang);
|
||||
VerificationCodeMsg = GetStringResource(IdentityMessagesKeys.VerificationCodeMsg, lang);
|
||||
NewDeviceLoggedInMsg = GetStringResource(IdentityMessagesKeys.NewDeviceLoggedInMsg, lang);
|
||||
RegistrationApproveMsg = GetStringResource(IdentityMessagesKeys.RegistrationApproveMsg, lang);
|
||||
|
||||
//
|
||||
if (!IsReady())
|
||||
{
|
||||
XException.InvalidArgs.Throw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using IdentityServer4.Extensions;
|
||||
using IdentityServer4.Models;
|
||||
using IdentityServer4.Services;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using xCommons.Extensions;
|
||||
using xIdentityModels;
|
||||
using xIds.Interfaces;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public class XIdentityProfileService : IProfileService
|
||||
{
|
||||
private readonly IXIdentityManager identityManager;
|
||||
private readonly IUserClaimsPrincipalFactory<XUser> userClaimsPrincipalFacotry;
|
||||
|
||||
public XIdentityProfileService(
|
||||
IXIdentityManager identityManager,
|
||||
IUserClaimsPrincipalFactory<XUser> userClaimsPrincipalFacotry
|
||||
)
|
||||
{
|
||||
this.identityManager = identityManager;
|
||||
this.userClaimsPrincipalFacotry = userClaimsPrincipalFacotry;
|
||||
}
|
||||
|
||||
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
|
||||
{
|
||||
//
|
||||
var sub = context.Subject.GetSubjectId();
|
||||
var user = await identityManager.GetUserAsync(sub, true);
|
||||
var principal = await userClaimsPrincipalFacotry.CreateAsync(user);
|
||||
|
||||
//
|
||||
var claims = principal.Claims.ToList();
|
||||
|
||||
//
|
||||
context.IssuedClaims = claims;
|
||||
}
|
||||
|
||||
public async Task IsActiveAsync(IsActiveContext context)
|
||||
{
|
||||
//
|
||||
var sub = context.Subject.GetSubjectId();
|
||||
var user = await identityManager.GetUserAsync(sub);
|
||||
|
||||
//
|
||||
context.IsActive = !user.IsNull() && user.IsEnable && !user.IsBanned;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using xCommons.Extensions;
|
||||
using xCommons.Providers;
|
||||
using xIds.Configurations;
|
||||
using xIds.Interfaces;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
public class XSecurityProvider : IXSecurityProvider
|
||||
{
|
||||
//
|
||||
#region Props ...
|
||||
private readonly string secretKey;
|
||||
private readonly byte[] iv;
|
||||
private readonly byte[] key;
|
||||
private readonly XValidationProvider validationProvider;
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Constructor ...
|
||||
public XSecurityProvider(
|
||||
XIdentityResourceConfiguration identityConfiguration,
|
||||
XValidationProvider validationProvider
|
||||
)
|
||||
{
|
||||
//
|
||||
this.secretKey = identityConfiguration.XRevisionSecretKey.ToMd5String();
|
||||
this.validationProvider = validationProvider;
|
||||
|
||||
//
|
||||
var ivBytes = new byte[16];
|
||||
var keyBytes = new byte[32];
|
||||
var secretBytes = Encoding.UTF8.GetBytes(this.secretKey);
|
||||
|
||||
//
|
||||
Array.Copy(
|
||||
secretBytes,
|
||||
ivBytes,
|
||||
secretBytes.Length < ivBytes.Length ?
|
||||
secretBytes.Length :
|
||||
ivBytes.Length
|
||||
);
|
||||
this.iv = ivBytes;
|
||||
|
||||
//
|
||||
Array.Copy(
|
||||
secretBytes,
|
||||
keyBytes,
|
||||
secretBytes.Length < keyBytes.Length ?
|
||||
secretBytes.Length :
|
||||
keyBytes.Length
|
||||
);
|
||||
this.key = keyBytes;
|
||||
|
||||
// Encoding.UTF8.GetBytes (this.secretKey);
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Actions ...
|
||||
public string Encrypt(string plainText)
|
||||
{
|
||||
//
|
||||
validationProvider.NotEmpty(plainText);
|
||||
|
||||
//
|
||||
var textBytes = Encoding.UTF8.GetBytes(plainText);
|
||||
var result = EncryptFromBytes(textBytes);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
public string Decrypt(string cipherText)
|
||||
{
|
||||
//
|
||||
validationProvider.NotEmpty(cipherText);
|
||||
|
||||
//
|
||||
var cipherBytes = Convert.FromBase64String(cipherText);
|
||||
var result = DecryptFromBytes(cipherBytes);
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
public string EncryptFromBytes(byte[] textBytes)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
validationProvider.NotNull(textBytes);
|
||||
|
||||
// Declare the string used to hold
|
||||
// the decrypted text.
|
||||
byte[] encryptedBytes = null;
|
||||
|
||||
// Create an RijndaelManaged object
|
||||
// with the specified key and IV.
|
||||
using (var rijAlg = new RijndaelManaged())
|
||||
{
|
||||
//Settings
|
||||
rijAlg.Mode = CipherMode.CBC;
|
||||
rijAlg.Padding = PaddingMode.PKCS7;
|
||||
// rijAlg.FeedbackSize = 128;
|
||||
|
||||
rijAlg.Key = key;
|
||||
rijAlg.IV = iv;
|
||||
|
||||
//
|
||||
using (var encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV))
|
||||
{
|
||||
encryptedBytes = encryptor.TransformFinalBlock(textBytes, 0, textBytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return Convert.ToBase64String(encryptedBytes);
|
||||
}
|
||||
|
||||
public string DecryptFromBytes(byte[] cipherBytes)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
validationProvider.NotNull(cipherBytes);
|
||||
|
||||
// Declare the string used to hold
|
||||
// the decrypted text.
|
||||
string plaintext = null;
|
||||
|
||||
// Create an RijndaelManaged object
|
||||
// with the specified key and IV.
|
||||
using (var rijAlg = new RijndaelManaged())
|
||||
{
|
||||
//Settings
|
||||
rijAlg.Mode = CipherMode.CBC;
|
||||
rijAlg.Padding = PaddingMode.PKCS7;
|
||||
// rijAlg.FeedbackSize = 128;
|
||||
|
||||
rijAlg.Key = key;
|
||||
rijAlg.IV = iv;
|
||||
|
||||
// Create a decrytor to perform the stream transform.
|
||||
var decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
|
||||
|
||||
// Create the streams used for decryption.
|
||||
using (var msDecrypt = new MemoryStream(cipherBytes))
|
||||
{
|
||||
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
|
||||
{
|
||||
using (var srDecrypt = new StreamReader(csDecrypt))
|
||||
{
|
||||
// Read the decrypted bytes from the decrypting stream
|
||||
// and place them in a string.
|
||||
plaintext = srDecrypt.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
return plaintext;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# xSaherElm.xIds
|
||||
|
||||
this project is an Identity Server for xSaherElm projects which provides Authentication and
|
||||
Authorization of User's.
|
||||
|
||||
## Maintainer
|
||||
|
||||
Hadi Khazaee asl
|
||||
|
||||
[https://www.saherelm.ir](https://www.saherelm.ir)
|
||||
|
||||
[hadi_khazaee_asl@yahoo.com](mailto:hadi_khazaee_asl@yahoo.com)
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using xCommons.Configurations;
|
||||
using xCommons.Extensions;
|
||||
using xStorageService.DI;
|
||||
using xIds.Constants;
|
||||
using xIds.DI;
|
||||
using xIds.Interfaces;
|
||||
using xIds.Providers;
|
||||
|
||||
namespace xIds
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
//
|
||||
// Register Validation Provider and all XCommons Module Services ...
|
||||
services.AddXCommons();
|
||||
|
||||
//
|
||||
// Register App Configuration ...
|
||||
services.AddXAppConfiguration(Configuration);
|
||||
var appConfiguration = services.GetRegisteredService<XAppConfiguration>();
|
||||
|
||||
//
|
||||
// Register XDataService Configuration ...
|
||||
services.AddXDataServiceConfiguration(Configuration, ConnectionStringNames.IDENTITY_CONNECTION_NAME);
|
||||
|
||||
//
|
||||
// Register Allowed Origins ...
|
||||
services.AddXCors(appConfiguration.AllowedOrigins);
|
||||
|
||||
//
|
||||
// Register Swagger ...
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
services.AddXSwagger(Configuration, xmlFilePath: xmlPath);
|
||||
|
||||
//
|
||||
// Register IdentityServer to DI ...
|
||||
// services.AddInMemoryXIdentityServer (Configuration);
|
||||
services.AddEfSupportXIdentityServer(Configuration);
|
||||
|
||||
//
|
||||
services.AddControllers()
|
||||
.AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
|
||||
|
||||
//
|
||||
// Register Authentication ...
|
||||
services.AddXIdentityServerAuthentication(Configuration);
|
||||
|
||||
//
|
||||
// Register Authorization ...
|
||||
services.AddXAuthorization();
|
||||
|
||||
//
|
||||
// Register Security Provider ...
|
||||
services.AddSingleton<IXSecurityProvider, XSecurityProvider>();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
|
||||
{
|
||||
//
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
//
|
||||
app.UseDeveloperExceptionPage();
|
||||
|
||||
//
|
||||
// app.UseXRequestLogger();
|
||||
}
|
||||
|
||||
//
|
||||
// Use Swagger Middleware ...
|
||||
app.UseXSwagger();
|
||||
|
||||
//
|
||||
app.UseHttpsRedirection();
|
||||
app.UseXForwardOptions();
|
||||
|
||||
//
|
||||
// Using Cors ...
|
||||
app.UseXCors();
|
||||
|
||||
//
|
||||
// Force App to Use IdentityServer ...
|
||||
app.UseXIdentityServer(logger);
|
||||
|
||||
//
|
||||
// Force app to Use Storage Service ...
|
||||
app.UseXStorageService();
|
||||
|
||||
//
|
||||
app.UseRouting();
|
||||
|
||||
//
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
//
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapDefaultControllerRoute();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using IdentityServer4.EntityFramework.DbContexts;
|
||||
using IdentityServer4.EntityFramework.Mappers;
|
||||
using IdentityServer4.Models;
|
||||
using IdentityServer4.Stores;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace xIds.Stores
|
||||
{
|
||||
public class XPersistedGrantStore : IPersistedGrantStore
|
||||
{
|
||||
private readonly PersistedGrantDbContext dbContext;
|
||||
|
||||
public XPersistedGrantStore(PersistedGrantDbContext dbContext)
|
||||
{
|
||||
this.dbContext = dbContext;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<PersistedGrant>> GetAllAsync(string subjectId)
|
||||
{
|
||||
//
|
||||
var result = (await dbContext.PersistedGrants
|
||||
.Where(g => g.SubjectId == subjectId)
|
||||
.AsNoTracking()
|
||||
.Select(res => res.ToModel())
|
||||
.ToListAsync()).AsEnumerable();
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<PersistedGrant> GetAsync(string key)
|
||||
{
|
||||
//
|
||||
var result = await dbContext.PersistedGrants
|
||||
.FirstOrDefaultAsync(g => g.Key == key);
|
||||
|
||||
//
|
||||
return result.ToModel();
|
||||
}
|
||||
|
||||
public async Task RemoveAllAsync(string subjectId, string clientId)
|
||||
{
|
||||
//
|
||||
var items = await dbContext.PersistedGrants
|
||||
.Where(g =>
|
||||
g.SubjectId == subjectId &&
|
||||
g.ClientId == clientId)
|
||||
.ToListAsync();
|
||||
|
||||
//
|
||||
dbContext.PersistedGrants.RemoveRange(items);
|
||||
|
||||
//
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task RemoveAllAsync(string subjectId, string clientId, string type)
|
||||
{
|
||||
//
|
||||
var items = await dbContext.PersistedGrants
|
||||
.Where(g =>
|
||||
g.SubjectId == subjectId &&
|
||||
g.ClientId == clientId &&
|
||||
g.Type == type)
|
||||
.ToListAsync();
|
||||
|
||||
//
|
||||
dbContext.PersistedGrants.RemoveRange(items);
|
||||
|
||||
//
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task RemoveAsync(string key)
|
||||
{
|
||||
//
|
||||
var items = await dbContext.PersistedGrants
|
||||
.Where(g => g.Key == key)
|
||||
.ToListAsync();
|
||||
|
||||
//
|
||||
dbContext.PersistedGrants.RemoveRange(items);
|
||||
|
||||
//
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> IsExistsAsync(string key)
|
||||
{
|
||||
return await this.dbContext.PersistedGrants.AnyAsync(g => g.Key == key);
|
||||
}
|
||||
|
||||
public async Task<bool> IsExistsAsync(PersistedGrant grant)
|
||||
{
|
||||
return await IsExistsAsync(grant.Key);
|
||||
}
|
||||
|
||||
public async Task AddOrUpdateAsync(PersistedGrant grant)
|
||||
{
|
||||
//
|
||||
var isExists = await IsExistsAsync(grant);
|
||||
if (isExists)
|
||||
{
|
||||
await UpdateAsync(grant);
|
||||
}
|
||||
else
|
||||
{
|
||||
await AddAsync(grant);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task AddAsync(PersistedGrant grant)
|
||||
{
|
||||
//
|
||||
var item = grant.ToEntity();
|
||||
await dbContext.PersistedGrants.AddAsync(item);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(PersistedGrant grant)
|
||||
{
|
||||
//
|
||||
var item = grant.ToEntity();
|
||||
var entity = dbContext.Attach(item);
|
||||
entity.State = EntityState.Modified;
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task StoreAsync(PersistedGrant grant)
|
||||
{
|
||||
await AddOrUpdateAsync(grant);
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: Complete this ...
|
||||
public Task<IEnumerable<PersistedGrant>> GetAllAsync(PersistedGrantFilter filter)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
//
|
||||
// TODO: Complete this ...
|
||||
public Task RemoveAllAsync(PersistedGrantFilter filter)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using IdentityServer4.Events;
|
||||
using IdentityServer4.Models;
|
||||
using IdentityServer4.Services;
|
||||
using IdentityServer4.Validation;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels.Navigations;
|
||||
using xIds.Interfaces;
|
||||
using static IdentityModel.OidcConstants;
|
||||
|
||||
namespace xIds.Validators
|
||||
{
|
||||
public class XResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
|
||||
{
|
||||
private readonly IXIdentityManager identityManager;
|
||||
private readonly IEventService events;
|
||||
private readonly ILogger<XResourceOwnerPasswordValidator> logger;
|
||||
|
||||
public XResourceOwnerPasswordValidator(
|
||||
IXIdentityManager identityProvider,
|
||||
IEventService events,
|
||||
ILogger<XResourceOwnerPasswordValidator> logger
|
||||
)
|
||||
{
|
||||
this.identityManager = identityProvider;
|
||||
this.events = events;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the resource owner password credential
|
||||
/// by providing UserName/Email or PhoneNumber
|
||||
/// </summary>
|
||||
/// <param name="context">The context.</param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
|
||||
{
|
||||
//
|
||||
var clientId = context.Request?.Client?.ClientId;
|
||||
var xUser = await identityManager.GetUserAsync(context.UserName, true);
|
||||
|
||||
//
|
||||
// Check Force Data ...
|
||||
var isForced = true;
|
||||
var isForcedStr = context.Request?.Raw["force"];
|
||||
if (!isForcedStr.IsNullOrEmpty())
|
||||
{
|
||||
isForced = isForcedStr.FromJSON<bool>();
|
||||
}
|
||||
|
||||
//
|
||||
XDevice device = null;
|
||||
var language = context.Request?.Raw["language"];
|
||||
var deviceStr = context.Request?.Raw["device"];
|
||||
if (deviceStr.IsNullOrEmpty() && isForced)
|
||||
{
|
||||
//
|
||||
logger.LogError($"Device not Found ...");
|
||||
|
||||
//
|
||||
await events
|
||||
.RaiseAsync(
|
||||
new UserLoginFailureEvent(
|
||||
xUser.UserName,
|
||||
XException.InvalidDevice.ToXError().Message,
|
||||
false,
|
||||
clientId
|
||||
));
|
||||
return;
|
||||
}
|
||||
device = isForced ? deviceStr.FromJSON<XDevice>() : null;
|
||||
|
||||
//
|
||||
XException exception;
|
||||
if (!xUser.IsNull())
|
||||
{
|
||||
//
|
||||
var result = await identityManager
|
||||
.CheckPasswordSignInAsync(
|
||||
xUser,
|
||||
context.Password,
|
||||
device,
|
||||
language,
|
||||
true,
|
||||
isForced
|
||||
);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
//
|
||||
logger.LogInformation("Credentials validated for username: {username}", xUser.UserName);
|
||||
|
||||
//
|
||||
// Update User Last Login ...
|
||||
xUser.LastLogin = DateTime.UtcNow;
|
||||
await identityManager.UpdateUserAsync(xUser);
|
||||
|
||||
//
|
||||
await events.RaiseAsync(
|
||||
new UserLoginSuccessEvent(
|
||||
xUser.UserName, xUser.Id, xUser.UserName, false, clientId
|
||||
));
|
||||
|
||||
//
|
||||
context.Result = new GrantValidationResult(xUser.Id, AuthenticationMethods.Password);
|
||||
return;
|
||||
}
|
||||
else if (result.IsLockedOut)
|
||||
{
|
||||
//
|
||||
logger.LogInformation("Authentication failed for username: {username}, reason: locked out", xUser.UserName);
|
||||
|
||||
//
|
||||
exception = XException.AccountLockedOut;
|
||||
await events
|
||||
.RaiseAsync(
|
||||
new UserLoginFailureEvent(
|
||||
xUser.UserName,
|
||||
exception.ToXError().Message,
|
||||
false,
|
||||
clientId
|
||||
));
|
||||
}
|
||||
else if (result.IsNotAllowed)
|
||||
{
|
||||
//
|
||||
logger.LogInformation("Authentication failed for username: {username}, reason: not allowed", xUser.UserName);
|
||||
|
||||
//
|
||||
exception = XException.NotAllowed;
|
||||
await events
|
||||
.RaiseAsync(
|
||||
new UserLoginFailureEvent(
|
||||
xUser.UserName,
|
||||
exception.ToXError().Message,
|
||||
false,
|
||||
clientId
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
logger.LogInformation("Authentication failed for username: {username}, reason: invalid credentials", xUser.UserName);
|
||||
|
||||
//
|
||||
exception = XException.LoginFailed;
|
||||
await events
|
||||
.RaiseAsync(
|
||||
new UserLoginFailureEvent(
|
||||
xUser.UserName,
|
||||
exception.ToXError().Message,
|
||||
false,
|
||||
clientId
|
||||
));
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
logger.LogInformation("No user found matching username: {username}", xUser.UserName);
|
||||
|
||||
//
|
||||
exception = XException.InvalidUserName;
|
||||
await events
|
||||
.RaiseAsync(
|
||||
new UserLoginFailureEvent(
|
||||
xUser.UserName,
|
||||
exception.ToXError().Message,
|
||||
false,
|
||||
clientId
|
||||
));
|
||||
}
|
||||
|
||||
//
|
||||
Exception ecs = exception.ToException();
|
||||
if (exception == XException.AccountLockedOut && xUser.LockoutEnd.HasValue)
|
||||
{
|
||||
//
|
||||
var passedTime = xUser.LockoutEnd.Value.UtcDateTime;
|
||||
ecs = XException.AccountLockedOut
|
||||
.AddContentToException(passedTime.ToString());
|
||||
}
|
||||
|
||||
//
|
||||
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, ecs.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
{
|
||||
"AllowedOrigins": [
|
||||
"https://localhost:5001",
|
||||
"https://localhost:6001",
|
||||
"https://saherelm.ir",
|
||||
"https://api.saherelm.ir",
|
||||
"https://saherelmhub.ir",
|
||||
"https://api.saherelmhub.ir",
|
||||
"https://192.168.1.15:5001",
|
||||
"https://192.168.1.110:5001"
|
||||
],
|
||||
"IdentityResourceConfiguration": {
|
||||
"Authority": "https://localhost:4001",
|
||||
"ApiName": "xSaherElmAPI",
|
||||
"ApiSecret": "s@H@1694056",
|
||||
"ClientId": "xSaherElmAPIClient",
|
||||
"ClientSecret": "s@H@1694056",
|
||||
"XPoweredValue": "SaherElmITCenter",
|
||||
"XRevisionSecretKey": "SaherElmITCenter@1694056"
|
||||
},
|
||||
"StorageConfiguration": {
|
||||
"Authority": "https://localhost:4001",
|
||||
"IdentityAuthority": "https://localhost:4001",
|
||||
"Storage": "Storage",
|
||||
"Temp": "Temp",
|
||||
"Thumb": "Thumb",
|
||||
"Uploads": "Uploads",
|
||||
"Widgets": "Widgets",
|
||||
"Image": "Image",
|
||||
"Audio": "Audio",
|
||||
"Video": "Video",
|
||||
"Document": "Document",
|
||||
"FilePrefix": "xSaherElm_",
|
||||
"ThumbPrefix": "Thumb_",
|
||||
"ThumbSize": 512,
|
||||
"ThumbQuality": 72,
|
||||
"MaxFileSize": 41943040
|
||||
},
|
||||
"DbSeeder": {
|
||||
"UpdateExists": false,
|
||||
"Clients": [
|
||||
{
|
||||
"ClientId": "xSaherElmAPIClient",
|
||||
"ClientName": "Web Client of xSaherElm API",
|
||||
"ClientSecrets": [
|
||||
{
|
||||
"Description": null,
|
||||
"Value": "NKaAKXeE9Ws+VVGGHsmM9DUO84cla4+hvx8swP1uuEg=",
|
||||
"Expiration": null,
|
||||
"Type": "SharedSecret"
|
||||
}
|
||||
],
|
||||
"Enabled": true,
|
||||
"RedirectUris": [
|
||||
"https://localhost:5001/signin-oidc"
|
||||
],
|
||||
"AllowedGrantTypes": [
|
||||
"hybrid",
|
||||
"password",
|
||||
"client_credentials"
|
||||
],
|
||||
"AllowedScopes": [
|
||||
"IdentityServerApi",
|
||||
"openid",
|
||||
"profile",
|
||||
"XAPI.read",
|
||||
"XAPI.write",
|
||||
"XAPI.admin",
|
||||
"manage",
|
||||
"offline_access"
|
||||
],
|
||||
"AllowedCorsOrigins": [
|
||||
"https://localhost:5001",
|
||||
"https://localhost:6001",
|
||||
"http://saherelm.ir",
|
||||
"https://saherelm.ir",
|
||||
"http://saherelmhub.ir",
|
||||
"https://saherelmhub.ir"
|
||||
],
|
||||
"AllowOfflineAccess": true,
|
||||
"RefreshTokenUsage": 1,
|
||||
"AccessTokenType": 1,
|
||||
"RefreshTokenExpiration": 0,
|
||||
"AbsoluteRefreshTokenLifetime": 2592000,
|
||||
"SlidingRefreshTokenLifetime": 1296000,
|
||||
"UpdateAccessTokenClaimsOnRefresh": true,
|
||||
"IdentityTokenLifetime": 300,
|
||||
"AccessTokenLifetime": 3600,
|
||||
"AuthorizationCodeLifetime": 300,
|
||||
"DeviceCodeLifetime": 300
|
||||
}
|
||||
],
|
||||
"IdentityResources": [
|
||||
"openid",
|
||||
"profile",
|
||||
"email",
|
||||
"role"
|
||||
],
|
||||
"ApiResources": [
|
||||
{
|
||||
"Name": "IdentityServerApi"
|
||||
},
|
||||
{
|
||||
"Name": "xSaherElmAPI",
|
||||
"DisplayName": "xSaherElm API",
|
||||
"Description": "Protected by IdentityServer API Access",
|
||||
"ApiSecrets": [
|
||||
{
|
||||
"Description": null,
|
||||
"Value": "NKaAKXeE9Ws+VVGGHsmM9DUO84cla4+hvx8swP1uuEg=",
|
||||
"Expiration": null,
|
||||
"Type": "SharedSecret"
|
||||
}
|
||||
],
|
||||
"Enabled": true,
|
||||
"Scopes": [
|
||||
"openid",
|
||||
"profile",
|
||||
"XAPI.read",
|
||||
"XAPI.write",
|
||||
"XAPI.admin",
|
||||
"manage"
|
||||
],
|
||||
"UserClaims": [
|
||||
"name",
|
||||
"role",
|
||||
"unique_name",
|
||||
"gender",
|
||||
"birthdate",
|
||||
"picture",
|
||||
"email",
|
||||
"phone_number",
|
||||
"email_verified",
|
||||
"phone_number_verified",
|
||||
"is_enabled",
|
||||
"is_banned",
|
||||
"creation_date",
|
||||
"last_login",
|
||||
"given_name",
|
||||
"family_name"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ApiScopes": [
|
||||
{
|
||||
"Name": "IdentityServerApi"
|
||||
},
|
||||
{
|
||||
"Name": "xSaherElmAPI"
|
||||
},
|
||||
{
|
||||
"Name": "XAPI.read",
|
||||
"DisplayName": "Read Access for XAPI"
|
||||
},
|
||||
{
|
||||
"Name": "XAPI.write",
|
||||
"DisplayName": "Write Access for XAPI"
|
||||
},
|
||||
{
|
||||
"Name": "XAPI.admin",
|
||||
"DisplayName": "Admin Access for XAPI"
|
||||
},
|
||||
{
|
||||
"Name": "manage",
|
||||
"DisplayName": "Admin Access for All APIs"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
@@ -0,0 +1,397 @@
|
||||
{
|
||||
"Version": "0.1",
|
||||
"XPoweredValue": "SaherElmITCenter",
|
||||
"Name": "xIdentityServer",
|
||||
"WelcomeMessage": "Welcome to xSaherElm Project's xIdentityServer",
|
||||
"AllowedOrigins": [
|
||||
"https://saherelm.ir",
|
||||
"https://saherelmhub.ir",
|
||||
"https://api.saherelm.ir",
|
||||
"https://api.saherelmhub.ir"
|
||||
],
|
||||
"SwaggerConfiguration": {
|
||||
"Version": "v1.0",
|
||||
"Title": "xSaherElm Identity Server API",
|
||||
"Description": "Complete API Documentation",
|
||||
"Contact": {
|
||||
"Name": "Hadi Khazaee Asl",
|
||||
"Email": "hadi_khazaee_asl@yahoo.com",
|
||||
"Url": "https://www.saherelm.ir"
|
||||
}
|
||||
},
|
||||
"DbProvider": "SQLite",
|
||||
"ConnectionStrings": {
|
||||
"IdentityDb": "Filename=./Db/XIdentity.db;Foreign Keys=False",
|
||||
"ConfigurationDb": "Filename=./Db/XConfigurations.db",
|
||||
"PersistedGrantDb": "Filename=./Db/XPersistedGrants.db"
|
||||
},
|
||||
"DataServiceConfiguration": {
|
||||
"PagingConfiguration": {
|
||||
"DefaultPageSize": 20,
|
||||
"MaxAvailablePageSize": 400,
|
||||
"MinAvailablePageSize": 20
|
||||
}
|
||||
},
|
||||
"Certificates": {
|
||||
"IdentityServerSigning": {
|
||||
"Path": "Certificate/xIds.pfx",
|
||||
"Secret": "s@1694056"
|
||||
}
|
||||
},
|
||||
"IdentityConfiguration": {
|
||||
"IdentityIssuer": "SaherElm Identity Server",
|
||||
"IdentityAudience": "SaherElmIdentityAPI",
|
||||
"IdentitySecretKey": "SaherElmITCenter@1694056",
|
||||
"ActionTokenExpirationDateProvider": "20m",
|
||||
"IdentityRoles": [
|
||||
"admin",
|
||||
"responsible_manager",
|
||||
"journalist",
|
||||
"chief_clerk",
|
||||
"chief_clerk_assistant",
|
||||
"actuary",
|
||||
"actuary_assistant",
|
||||
"reporter",
|
||||
"reporter_assistant",
|
||||
"agent",
|
||||
"user"
|
||||
],
|
||||
"AutoConfirmNewUsersEmail": false,
|
||||
"AutoConfirmNewUsersPhoneNumber": false,
|
||||
"RegistrationJustWithInvite": false,
|
||||
"RequireRegistrationConfirm": true,
|
||||
"MaxNumberOfVerificationCodeSend": 3,
|
||||
"DeleyBetweenTwoVerificationCode": 180,
|
||||
"NewUsersRole": "user",
|
||||
"Policy": {
|
||||
"Lockout": {
|
||||
"LockoutTimeSpanProvider": "15m",
|
||||
"MaxFailedAccessAttempts": 5,
|
||||
"AllowedForNewUsers": true
|
||||
},
|
||||
"Password": {
|
||||
"RequireDigit": true,
|
||||
"RequiredLength": 6,
|
||||
"RequiredUniqueChars": 1,
|
||||
"RequireLowercase": true,
|
||||
"RequireNonAlphanumeric": true,
|
||||
"RequireUppercase": true
|
||||
},
|
||||
"SignIn": {
|
||||
"RequiredEnabled": true,
|
||||
"RequireConfirmedEmail": true,
|
||||
"RequireConfirmedPhoneNumber": false
|
||||
},
|
||||
"User": {
|
||||
"AllowedUserNameCharacters": "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._",
|
||||
"RequireUniqueEmail": true,
|
||||
"MinLength": 6,
|
||||
"MaxLength": 20,
|
||||
"MinAgeForRegistration": 18,
|
||||
"MaxAgeForRegistration": 60,
|
||||
"InvalidUserNames": [
|
||||
"saherelm",
|
||||
"admin",
|
||||
"responsible_manager",
|
||||
"journalist",
|
||||
"chief_clerk",
|
||||
"chief_clerk_assistant",
|
||||
"actuary",
|
||||
"actuary_assistant",
|
||||
"reporter",
|
||||
"reporter_assistant",
|
||||
"agent",
|
||||
"user"
|
||||
]
|
||||
},
|
||||
"Profile": {
|
||||
"ContainsEmail": false,
|
||||
"ContainsPhoneNumber": false,
|
||||
"ContainsRoles": true,
|
||||
"ContainsLastLogin": false,
|
||||
"ContainsDateOfBirth": false,
|
||||
"ContainsCreationDate": true
|
||||
}
|
||||
},
|
||||
"IdentityMessages": [
|
||||
{
|
||||
"Language": "fa-IR",
|
||||
"ResourceTitle": "user_invite_msg",
|
||||
"TranslatedValue": "شما دعوت شده اید تا در سامانه ثبت نام کنید"
|
||||
},
|
||||
{
|
||||
"Language": "en-US",
|
||||
"ResourceTitle": "user_invite_msg",
|
||||
"TranslatedValue": "You are Invited to Register at Dashboard"
|
||||
},
|
||||
{
|
||||
"Language": "fa-IR",
|
||||
"ResourceTitle": "registration_approve_msg",
|
||||
"TranslatedValue": "شما باید حساب کاربری خود را با ورود به پیوند زیر فعال کنید"
|
||||
},
|
||||
{
|
||||
"Language": "en-US",
|
||||
"ResourceTitle": "registration_approve_msg",
|
||||
"TranslatedValue": "you must activate your account by going to this link"
|
||||
},
|
||||
{
|
||||
"Language": "fa-IR",
|
||||
"ResourceTitle": "registered_msg",
|
||||
"TranslatedValue": "ثبت نام شما در سامانه با موفقیت پایان یافت"
|
||||
},
|
||||
{
|
||||
"Language": "en-US",
|
||||
"ResourceTitle": "registered_msg",
|
||||
"TranslatedValue": "you successfully registered at Dashboard"
|
||||
},
|
||||
{
|
||||
"Language": "fa-IR",
|
||||
"ResourceTitle": "verification_code_msg",
|
||||
"TranslatedValue": "کد اعتبار سنجی شما در سامانه"
|
||||
},
|
||||
{
|
||||
"Language": "en-US",
|
||||
"ResourceTitle": "verification_code_msg",
|
||||
"TranslatedValue": "Your Verification Code at Dashboard"
|
||||
},
|
||||
{
|
||||
"Language": "fa-IR",
|
||||
"ResourceTitle": "change_password_msg",
|
||||
"TranslatedValue": "برای تغییر کلمه عبور پیوند زیر را دنبال کنید"
|
||||
},
|
||||
{
|
||||
"Language": "en-US",
|
||||
"ResourceTitle": "change_password_msg",
|
||||
"TranslatedValue": "for change password please follow this link"
|
||||
},
|
||||
{
|
||||
"Language": "fa-IR",
|
||||
"ResourceTitle": "password_changed_msg",
|
||||
"TranslatedValue": "کلمه عبور شما در سامانه تغییر یافت"
|
||||
},
|
||||
{
|
||||
"Language": "en-US",
|
||||
"ResourceTitle": "password_changed_msg",
|
||||
"TranslatedValue": "your password at Dashboard changed"
|
||||
},
|
||||
{
|
||||
"Language": "fa-IR",
|
||||
"ResourceTitle": "new_device_logged_in_msg",
|
||||
"TranslatedValue": "ابزار جدیدی با مشخصات ذیل در سامانه با حساب کاربری شما وارد شده است"
|
||||
},
|
||||
{
|
||||
"Language": "en-US",
|
||||
"ResourceTitle": "new_device_logged_in_msg",
|
||||
"TranslatedValue": "new device with following details loggedin with your account in Dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"IdentityResourceConfiguration": {
|
||||
"Authority": "https://172.18.0.151",
|
||||
"ApiName": "xSaherElmAPI",
|
||||
"ApiSecret": "s@H@1694056",
|
||||
"ClientId": "xSaherElmAPIClient",
|
||||
"ClientSecret": "s@H@1694056",
|
||||
"XPoweredValue": "SaherElmITCenter",
|
||||
"XRevisionSecretKey": "SaherElmITCenter@1694056"
|
||||
},
|
||||
"StorageConfiguration": {
|
||||
"Authority": "https://ids.saherelm.ir",
|
||||
"IdentityAuthority": "https://ids.saherelm.ir",
|
||||
"Storage": "Storage",
|
||||
"Temp": "Temp",
|
||||
"Thumb": "Thumb",
|
||||
"Uploads": "Uploads",
|
||||
"Widgets": "Widgets",
|
||||
"Image": "Image",
|
||||
"Audio": "Audio",
|
||||
"Video": "Video",
|
||||
"Document": "Document",
|
||||
"FilePrefix": "xSaherElm_",
|
||||
"ThumbPrefix": "Thumb_",
|
||||
"ThumbSize": 512,
|
||||
"ThumbQuality": 72,
|
||||
"MaxFileSize": 41943040
|
||||
},
|
||||
"MessageConfiguration": {
|
||||
"MailConfigurations": {
|
||||
"gmail": {
|
||||
"Title": "SaherElm Dashboard",
|
||||
"Host": "smtp.gmail.com",
|
||||
"Port": 587,
|
||||
"EnableSsl": true,
|
||||
"Username": "saherelm@gmail.com",
|
||||
"Password": "vzuz gtrk tndb ctbc"
|
||||
}
|
||||
},
|
||||
"SmsConfigurations": {
|
||||
"yoursms": {
|
||||
"ServiceUrl": "http://sms.yourprovider.ir",
|
||||
"Username": "user",
|
||||
"Password": "psw",
|
||||
"LineNumber": "linenumber",
|
||||
"UserApiKey": "",
|
||||
"SecretKey": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"DbSeeder": {
|
||||
"UpdateExists": false,
|
||||
"Clients": [
|
||||
{
|
||||
"ClientId": "xSaherElmAPIClient",
|
||||
"ClientName": "Web Client of xMabsut API",
|
||||
"ClientSecrets": [
|
||||
{
|
||||
"Description": null,
|
||||
"Value": "NKaAKXeE9Ws+VVGGHsmM9DUO84cla4+hvx8swP1uuEg=",
|
||||
"Expiration": null,
|
||||
"Type": "SharedSecret"
|
||||
}
|
||||
],
|
||||
"Enabled": true,
|
||||
"RedirectUris": ["https://localhost:5001/signin-oidc"],
|
||||
"AllowedGrantTypes": [
|
||||
"hybrid",
|
||||
"password",
|
||||
"client_credentials"
|
||||
],
|
||||
"AllowedScopes": [
|
||||
"IdentityServerApi",
|
||||
"openid",
|
||||
"profile",
|
||||
"XAPI.read",
|
||||
"XAPI.write",
|
||||
"XAPI.admin",
|
||||
"manage",
|
||||
"offline_access"
|
||||
],
|
||||
"AllowedCorsOrigins": [
|
||||
"http://saherelm.ir",
|
||||
"https://saherelm.ir",
|
||||
"http://saherelmhub.ir",
|
||||
"https://saherelmhub.ir"
|
||||
],
|
||||
"AllowOfflineAccess": true,
|
||||
"RefreshTokenUsage": 1,
|
||||
"AccessTokenType": 1,
|
||||
"RefreshTokenExpiration": 0,
|
||||
"AbsoluteRefreshTokenLifetime": 2592000,
|
||||
"SlidingRefreshTokenLifetime": 1296000,
|
||||
"UpdateAccessTokenClaimsOnRefresh": true,
|
||||
"IdentityTokenLifetime": 300,
|
||||
"AccessTokenLifetime": 3600,
|
||||
"AuthorizationCodeLifetime": 300,
|
||||
"DeviceCodeLifetime": 300
|
||||
}
|
||||
],
|
||||
"IdentityResources": ["openid", "profile", "email", "role"],
|
||||
"ApiResources": [
|
||||
{
|
||||
"Name": "IdentityServerApi"
|
||||
},
|
||||
{
|
||||
"Name": "xSaherElmAPI",
|
||||
"DisplayName": "xSaherElm API",
|
||||
"Description": "Protected by IdentityServer API Access",
|
||||
"ApiSecrets": [
|
||||
{
|
||||
"Description": null,
|
||||
"Value": "NKaAKXeE9Ws+VVGGHsmM9DUO84cla4+hvx8swP1uuEg=",
|
||||
"Expiration": null,
|
||||
"Type": "SharedSecret"
|
||||
}
|
||||
],
|
||||
"Enabled": true,
|
||||
"Scopes": [
|
||||
"openid",
|
||||
"profile",
|
||||
"XAPI.read",
|
||||
"XAPI.write",
|
||||
"XAPI.admin",
|
||||
"manage"
|
||||
],
|
||||
"UserClaims": [
|
||||
"name",
|
||||
"role",
|
||||
"unique_name",
|
||||
"gender",
|
||||
"birthdate",
|
||||
"picture",
|
||||
"email",
|
||||
"phone_number",
|
||||
"email_verified",
|
||||
"phone_number_verified",
|
||||
"is_enabled",
|
||||
"is_banned",
|
||||
"creation_date",
|
||||
"last_login",
|
||||
"given_name",
|
||||
"family_name"
|
||||
]
|
||||
}
|
||||
],
|
||||
"ApiScopes": [
|
||||
{
|
||||
"Name": "IdentityServerApi"
|
||||
},
|
||||
{
|
||||
"Name": "xSaherElmAPI"
|
||||
},
|
||||
{
|
||||
"Name": "XAPI.read",
|
||||
"DisplayName": "Read Access for XAPI"
|
||||
},
|
||||
{
|
||||
"Name": "XAPI.write",
|
||||
"DisplayName": "Write Access for XAPI"
|
||||
},
|
||||
{
|
||||
"Name": "XAPI.admin",
|
||||
"DisplayName": "Admin Access for XAPI"
|
||||
},
|
||||
{
|
||||
"Name": "manage",
|
||||
"DisplayName": "Admin Access for All APIs"
|
||||
}
|
||||
],
|
||||
"Users": [
|
||||
{
|
||||
"Id": "b5713f9f-34f4-49b2-9680-b71e2b2de969",
|
||||
"FirstName": "Hadi",
|
||||
"LastName": "Khazaee Asl",
|
||||
"UserName": "admin",
|
||||
"Email": "hadi_khazaee_asl@yahoo.com",
|
||||
"EmailConfirmed": true,
|
||||
"PhoneNumber": "+989121694056",
|
||||
"PhoneNumberConfirmed": true,
|
||||
"Password": "s@H@1694056",
|
||||
"Role": "admin",
|
||||
"DateOfBirth": "1982-09-17 20:30:00.0000000",
|
||||
"IsEnable": true
|
||||
},
|
||||
{
|
||||
"Id": "83b09f5e-edd2-4e9a-8c5f-c4c129ee9d52",
|
||||
"FirstName": "Hadi",
|
||||
"LastName": "Khazaee Asl",
|
||||
"UserName": "agent",
|
||||
"Email": "hadi.khazaee.asl@gmail.com",
|
||||
"EmailConfirmed": true,
|
||||
"PhoneNumber": "+989101879789",
|
||||
"PhoneNumberConfirmed": true,
|
||||
"Password": "a@A@1694056",
|
||||
"Role": "agent",
|
||||
"DateOfBirth": "1982-09-17 20:30:00.0000000",
|
||||
"IsEnable": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="nuget" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||
<add key="baget" value="https://nuget.saherelmhub.ir/v3/index.json" protocolVersion="3" />
|
||||
<add key="nugetIran" value="https://repo.nugetiran.ir/repository/nuget-group/v3/index.json" protocolVersion="3" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
@@ -0,0 +1 @@
|
||||
{"alg":"RS256","d":"ArwBivGf5QZR7tala9B6BmHJOVbPp_MQCGa1h9bXRhzZjpSC2Ppq3pFMLvu089GXvbgjgR5o_ORyP9OIKtvHkNKtwMV_z_Om3C864pAr4i1RdRtc5pwYNhFEZkEY8bZ6ne4KzTcqSZGw9rXjSWTna95bifHwM9m_UGtcHwljJnd-SXJjxRUWFTkCut1u1ACmhvuQeEQrHrJbL5pVBli80FinQzqG4CNGpk9pjiBPRfenp1ctzBSggIsX_lmCLHkvXPxl9Yy4i01DdOLCJUtYmf49TjP-MWUTz9IccrMJoX2iuh9iHaCafx5qq7k8L42DFR1tQS4hp3sKPQ3kXFqfkQ","dp":"TP1dStEZx2EeZF5Sz3PZJEqxFHe5Xa3zmhiGCe2Jm2wRZ04XOxzd2xw_cUoftAxemeMpRXq7KMarrD4WMFswX1yLK3LVO9WpdvEBBR7f-SIpVbKYdhP3P1zZqwudih6hbjaPd03G4CesbuActwtirc0323nxUXuZbTvkLztbYyc","dq":"sEXhyXCs-mDNNM_qKRCh7zIztQfc8LEFYXckZSk_1mnDA3WNQRqXXdXbLw0JkBBTHlALZoue8lfTyMfjqFkpSrl06qMKVU3SkF69omvemnuNeCKMFqItEkcynRuqf3vYsurxM6bXf57WdgDc708ZftWdXl9oo0baFh74yIlgsBk","e":"AQAB","kid":"38954A2B1CBC6B8ADFC020D8A81E7947","kty":"RSA","n":"rKTQ4bS9E8h_i7v-okGQPhqJ5V9xovOqCoqWlBGJ2osETHi05itedHMdK99t4Q8usI5cDkiI9AW1F59R-hFeXEyYxhrHoiYuU2HtstG-e5xFp2qLlbO_bGNCeLlEROnigWVMRYp7fsL3trb_VGTTTeFFn6-iuPVvhFvhBcxBEuisLtxmsywT58ucxdQa-2CDnA4UmGp8zI0BZPYGAdEXoCqlobtURdiSW8X1rxk96dHTy3sDzwofd-SWlJHcxz4DP6lCHTfxk3cxBY0KYTJbOhyzASiV8wJ0oMFQBeSB_5U4r0tOBIYZ_d_KwE_LQ-oxw-XN3Uv_qsy9w_0cy_FqEw","p":"1qnzbvQ2EdPz_gD4pVvf5NtoxqqDKxblhhWLYYFUQTEYmLvsoGh62oYv1F1e_CJm3DgwoDBzkrcAITdBmmYwqxcr7K3J_IZIN0R-tfLrqoE4L8pOwF3lvqGo7w5kzpaI3ofrgEfGjvypq698r3AqnqQ8saKKHgEvqJQ5aM1OyEc","q":"zeNyx4l6aBr4rhcw3lUmOTtxpcVMlo1WH5McjaUMFsh7Nd33nf9dB9gJlddu79SBwBXMVASWZ_bBzFCclb5viuvgvQgr1nbJq8hm3I52j9ZH1H4Nh05DYW2aiDo3HFf3FqMng3_mesu26cJrjBhir5Pxhx3OgBfuihCoOZs_gdU","qi":"i1RttjN0gRVILTzVdBZdBieXh5GYDiDcSvTy-rf4pg-6JBs5p7DyGFr9Fu5k5HZmzdqBecHTov-pZFC5PdDIUAU2DXaSWK0-UFhbNBxDgm8CcT_pW3_DjCve162Zb8QcZRLcg1jzovlQVwzw897ixJOlhm4JRDNKts_IHL6R4Do"}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<!-- Runtime Definitions -->
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<PackageId>xSaherElm.xIds</PackageId>
|
||||
<Version>1.0.0</Version>
|
||||
<Authors>Hadi Khazaee Asl</Authors>
|
||||
<Company>SaherElm IT Center</Company>
|
||||
<Description>
|
||||
this project is an Identity Server for xSaherElm projects which provides Authentication and
|
||||
Authorization of User's.
|
||||
</Description>
|
||||
|
||||
<!-- Fix Duplicate TargetFramework Issue -->
|
||||
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Local Dependencies -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xDashboard.xMessageService" Version="1.0.0" />
|
||||
<PackageReference Include="xDashboard.xStorageService" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Project Dependencies -->
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Modules\xIdentityHelper\xIdentityHelper.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- IdentityServer -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="IdentityServer4" Version="4.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
|
||||
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.1" />
|
||||
<PackageReference Include="IdentityServer4.EntityFramework" Version="4.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
|
||||
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.11" />
|
||||
<PackageReference Include="IdentityModel.AspNetCore.OAuth2Introspection" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.12" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.2" />
|
||||
<PackageReference Include="IdentityModel.AspNetCore.AccessTokenValidation"
|
||||
Version="1.0.0-preview.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Ef Core -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MySql.EntityFrameworkCore" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- For XML Documentation Support -->
|
||||
<PropertyGroup>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Create Required Folders -->
|
||||
<Target Name="CreateRequiredFolder" AfterTargets="AfterPublish">
|
||||
<MakeDir Directories="$(PublishDir)wwwroot" Condition="!Exists('$(PublishDir)wwwroot')" />
|
||||
</Target>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user