392 lines
13 KiB
C#
392 lines
13 KiB
C#
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
|
|
}
|
|
} |