first commit -push
This commit is contained in:
402
RobotNet.IdentityServer/Controllers/AuthorizationController.cs
Normal file
402
RobotNet.IdentityServer/Controllers/AuthorizationController.cs
Normal file
@@ -0,0 +1,402 @@
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using OpenIddict.Abstractions;
|
||||
using OpenIddict.Server.AspNetCore;
|
||||
using RobotNet.IdentityServer.Data;
|
||||
using RobotNet.IdentityServer.Helpers;
|
||||
using System.Security.Claims;
|
||||
using static OpenIddict.Abstractions.OpenIddictConstants;
|
||||
|
||||
namespace RobotNet.IdentityServer.Controllers;
|
||||
|
||||
[EnableCors("RequestAuthorize")]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class AuthorizationController(
|
||||
IOpenIddictApplicationManager applicationManager,
|
||||
IOpenIddictAuthorizationManager authorizationManager,
|
||||
IOpenIddictScopeManager scopeManager,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
UserManager<ApplicationUser> userManager) : ControllerBase
|
||||
{
|
||||
[HttpGet("connect/authorize")]
|
||||
[HttpPost("connect/authorize")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
public async Task<IActionResult> Authorize()
|
||||
{
|
||||
var request = HttpContext.GetOpenIddictServerRequest() ??
|
||||
throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
|
||||
|
||||
// Try to retrieve the user principal stored in the authentication cookie and redirect
|
||||
// the user agent to the login page (or to an external provider) in the following cases:
|
||||
//
|
||||
// - If the user principal can't be extracted or the cookie is too old.
|
||||
// - If prompt=login was specified by the client application.
|
||||
// - If a max_age parameter was provided and the authentication cookie is not considered "fresh" enough.
|
||||
//
|
||||
// For scenarios where the default authentication handler configured in the ASP.NET Core
|
||||
// authentication options shouldn't be used, a specific scheme can be specified here.
|
||||
var result = await HttpContext.AuthenticateAsync();
|
||||
if (result == null || !result.Succeeded || request.HasPromptValue(PromptValues.Login) ||
|
||||
(request.MaxAge != null && result.Properties?.IssuedUtc != null &&
|
||||
DateTimeOffset.UtcNow - result.Properties.IssuedUtc > TimeSpan.FromSeconds(request.MaxAge.Value)))
|
||||
{
|
||||
// If the client application requested promptless authentication,
|
||||
// return an error indicating that the user is not logged in.
|
||||
if (request.HasPromptValue(PromptValues.None))
|
||||
{
|
||||
return Forbid(
|
||||
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
|
||||
properties: new AuthenticationProperties(new Dictionary<string, string?>
|
||||
{
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.LoginRequired,
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is not logged in."
|
||||
}));
|
||||
}
|
||||
|
||||
// To avoid endless login -> authorization redirects, the prompt=login flag
|
||||
// is removed from the authorization request payload before redirecting the user.
|
||||
var prompt = string.Join(" ", request.GetPromptValues().Remove(PromptValues.Login));
|
||||
|
||||
var parameters = Request.HasFormContentType ?
|
||||
Request.Form.Where(parameter => parameter.Key != Parameters.Prompt).ToList() :
|
||||
Request.Query.Where(parameter => parameter.Key != Parameters.Prompt).ToList();
|
||||
|
||||
parameters.Add(KeyValuePair.Create(Parameters.Prompt, new StringValues(prompt)));
|
||||
|
||||
// For scenarios where the default challenge handler configured in the ASP.NET Core
|
||||
// authentication options shouldn't be used, a specific scheme can be specified here.
|
||||
return Challenge(new AuthenticationProperties
|
||||
{
|
||||
RedirectUri = Request.PathBase + Request.Path + QueryString.Create(parameters)
|
||||
});
|
||||
}
|
||||
|
||||
// Retrieve the profile of the logged in user.
|
||||
var user = await userManager.GetUserAsync(result.Principal) ??
|
||||
throw new InvalidOperationException("The user details cannot be retrieved.");
|
||||
|
||||
// Retrieve the application details from the database.
|
||||
var application = await applicationManager.FindByClientIdAsync(request.ClientId ?? "") ??
|
||||
throw new InvalidOperationException("Details concerning the calling client application cannot be found.");
|
||||
|
||||
// Retrieve the permanent authorizations associated with the user and the calling client application.
|
||||
var authorizations = await authorizationManager.FindAsync(
|
||||
subject: await userManager.GetUserIdAsync(user),
|
||||
client: await applicationManager.GetIdAsync(application),
|
||||
status: Statuses.Valid,
|
||||
type: AuthorizationTypes.Permanent,
|
||||
scopes: request.GetScopes()).ToListAsync();
|
||||
|
||||
switch (await applicationManager.GetConsentTypeAsync(application))
|
||||
{
|
||||
// If the consent is external (e.g when authorizations are granted by a sysadmin),
|
||||
// immediately return an error if no authorization can be found in the database.
|
||||
case ConsentTypes.External when authorizations.Count is 0:
|
||||
return Forbid(
|
||||
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
|
||||
properties: new AuthenticationProperties(new Dictionary<string, string?>
|
||||
{
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired,
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
|
||||
"The logged in user is not allowed to access this client application."
|
||||
}));
|
||||
|
||||
// If the consent is implicit or if an authorization was found,
|
||||
// return an authorization response without displaying the consent form.
|
||||
case ConsentTypes.Implicit:
|
||||
case ConsentTypes.External when authorizations.Count is not 0:
|
||||
case ConsentTypes.Explicit when authorizations.Count is not 0 && !request.HasPromptValue(PromptValues.Consent):
|
||||
// Create the claims-based identity that will be used by OpenIddict to generate tokens.
|
||||
var identity = new ClaimsIdentity(
|
||||
authenticationType: TokenValidationParameters.DefaultAuthenticationType,
|
||||
nameType: Claims.Name,
|
||||
roleType: Claims.Role);
|
||||
|
||||
// Add the claims that will be persisted in the tokens.
|
||||
identity.SetClaim(Claims.Subject, await userManager.GetUserIdAsync(user))
|
||||
.SetClaim(Claims.Email, await userManager.GetEmailAsync(user))
|
||||
.SetClaim(Claims.Name, await userManager.GetUserNameAsync(user))
|
||||
.SetClaim(Claims.PreferredUsername, await userManager.GetUserNameAsync(user))
|
||||
.SetClaims(Claims.Role, [.. (await userManager.GetRolesAsync(user))]);
|
||||
|
||||
// Note: in this sample, the granted scopes match the requested scope
|
||||
// but you may want to allow the user to uncheck specific scopes.
|
||||
// For that, simply restrict the list of scopes before calling SetScopes.
|
||||
identity.SetScopes(request.GetScopes());
|
||||
identity.SetResources(await scopeManager.ListResourcesAsync(identity.GetScopes()).ToListAsync());
|
||||
|
||||
// Automatically create a permanent authorization to avoid requiring explicit consent
|
||||
// for future authorization or token requests containing the same scopes.
|
||||
var authorization = authorizations.LastOrDefault();
|
||||
authorization ??= await authorizationManager.CreateAsync(
|
||||
identity: identity,
|
||||
subject: await userManager.GetUserIdAsync(user),
|
||||
client: await applicationManager.GetIdAsync(application) ?? "",
|
||||
type: AuthorizationTypes.Permanent,
|
||||
scopes: identity.GetScopes());
|
||||
|
||||
identity.SetAuthorizationId(await authorizationManager.GetIdAsync(authorization));
|
||||
identity.SetDestinations(GetDestinations);
|
||||
|
||||
return SignIn(new ClaimsPrincipal(identity), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
||||
|
||||
// At this point, no authorization was found in the database and an error must be returned
|
||||
// if the client application specified prompt=none in the authorization request.
|
||||
case ConsentTypes.Explicit when request.HasPromptValue(PromptValues.None):
|
||||
case ConsentTypes.Systematic when request.HasPromptValue(PromptValues.None):
|
||||
return Forbid(
|
||||
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
|
||||
properties: new AuthenticationProperties(new Dictionary<string, string?>
|
||||
{
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired,
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
|
||||
"Interactive user consent is required."
|
||||
}));
|
||||
|
||||
// In every other case, render the consent form.
|
||||
default:
|
||||
return Redirect($"/Account/Login/Access{Request.QueryString}&request_app={await applicationManager.GetLocalizedDisplayNameAsync(application)}&request_scope={request.Scope}");
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize, FormValueRequired("submit.Accept")]
|
||||
[HttpPost("connect/authorize"), ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Accept()
|
||||
{
|
||||
var request = HttpContext.GetOpenIddictServerRequest() ??
|
||||
throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
|
||||
|
||||
// Retrieve the profile of the logged in user.
|
||||
var user = await userManager.GetUserAsync(User) ??
|
||||
throw new InvalidOperationException("The user details cannot be retrieved.");
|
||||
|
||||
// Retrieve the application details from the database.
|
||||
var application = await applicationManager.FindByClientIdAsync(request.ClientId ?? "") ??
|
||||
throw new InvalidOperationException("Details concerning the calling client application cannot be found.");
|
||||
|
||||
// Retrieve the permanent authorizations associated with the user and the calling client application.
|
||||
var authorizations = await authorizationManager.FindAsync(
|
||||
subject: await userManager.GetUserIdAsync(user),
|
||||
client: await applicationManager.GetIdAsync(application),
|
||||
status: Statuses.Valid,
|
||||
type: AuthorizationTypes.Permanent,
|
||||
scopes: request.GetScopes()).ToListAsync();
|
||||
|
||||
// Note: the same check is already made in the other action but is repeated
|
||||
// here to ensure a malicious user can't abuse this POST-only endpoint and
|
||||
// force it to return a valid response without the external authorization.
|
||||
if (authorizations.Count is 0 && await applicationManager.HasConsentTypeAsync(application, ConsentTypes.External))
|
||||
{
|
||||
return Forbid(
|
||||
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
|
||||
properties: new AuthenticationProperties(new Dictionary<string, string?>
|
||||
{
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired,
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
|
||||
"The logged in user is not allowed to access this client application."
|
||||
}));
|
||||
}
|
||||
|
||||
// Create the claims-based identity that will be used by OpenIddict to generate tokens.
|
||||
var identity = new ClaimsIdentity(
|
||||
authenticationType: TokenValidationParameters.DefaultAuthenticationType,
|
||||
nameType: Claims.Name,
|
||||
roleType: Claims.Role);
|
||||
|
||||
// Add the claims that will be persisted in the tokens.
|
||||
identity.SetClaim(Claims.Subject, await userManager.GetUserIdAsync(user))
|
||||
.SetClaim(Claims.Email, await userManager.GetEmailAsync(user))
|
||||
.SetClaim(Claims.Name, await userManager.GetUserNameAsync(user))
|
||||
.SetClaim(Claims.PreferredUsername, await userManager.GetUserNameAsync(user))
|
||||
.SetClaims(Claims.Role, [.. (await userManager.GetRolesAsync(user))]);
|
||||
|
||||
// Note: in this sample, the granted scopes match the requested scope
|
||||
// but you may want to allow the user to uncheck specific scopes.
|
||||
// For that, simply restrict the list of scopes before calling SetScopes.
|
||||
identity.SetScopes(request.GetScopes());
|
||||
identity.SetResources(await scopeManager.ListResourcesAsync(identity.GetScopes()).ToListAsync());
|
||||
|
||||
// Automatically create a permanent authorization to avoid requiring explicit consent
|
||||
// for future authorization or token requests containing the same scopes.
|
||||
var authorization = authorizations.LastOrDefault();
|
||||
authorization ??= await authorizationManager.CreateAsync(
|
||||
identity: identity,
|
||||
subject: await userManager.GetUserIdAsync(user),
|
||||
client: await applicationManager.GetIdAsync(application) ?? "",
|
||||
type: AuthorizationTypes.Permanent,
|
||||
scopes: identity.GetScopes());
|
||||
|
||||
identity.SetAuthorizationId(await authorizationManager.GetIdAsync(authorization));
|
||||
identity.SetDestinations(GetDestinations);
|
||||
|
||||
// Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
|
||||
return SignIn(new ClaimsPrincipal(identity), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
||||
}
|
||||
|
||||
[Authorize, FormValueRequired("submit.Deny")]
|
||||
[HttpPost("connect/authorize"), ValidateAntiForgeryToken]
|
||||
// Notify OpenIddict that the authorization grant has been denied by the resource owner
|
||||
// to redirect the user agent to the client application using the appropriate response_mode.
|
||||
public IActionResult Deny() => Forbid(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
||||
|
||||
[HttpGet("connect/logout")]
|
||||
public IActionResult Logout() => Redirect($"/Account/Logout/Confirm{Request.QueryString}");
|
||||
|
||||
//[ActionName(nameof(Logout)), HttpPost("connect/logout"), ValidateAntiForgeryToken]
|
||||
[Authorize, FormValueRequired("submit.Confirm")]
|
||||
[HttpPost("connect/logout"), ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> LogoutPost()
|
||||
{
|
||||
// Ask ASP.NET Core Identity to delete the local and external cookies created
|
||||
// when the user agent is redirected from the external identity provider
|
||||
// after a successful authentication flow (e.g Google or Facebook).
|
||||
await signInManager.SignOutAsync();
|
||||
|
||||
// Returning a SignOutResult will ask OpenIddict to redirect the user agent
|
||||
// to the post_logout_redirect_uri specified by the client application or to
|
||||
// the RedirectUri specified in the authentication properties if none was set.
|
||||
return SignOut(
|
||||
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
|
||||
properties: new AuthenticationProperties
|
||||
{
|
||||
RedirectUri = "/"
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("connect/token"), IgnoreAntiforgeryToken, Produces("application/json")]
|
||||
public async Task<IActionResult> Exchange()
|
||||
{
|
||||
var request = HttpContext.GetOpenIddictServerRequest() ??
|
||||
throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
|
||||
|
||||
if (request.IsAuthorizationCodeGrantType() || request.IsRefreshTokenGrantType())
|
||||
{
|
||||
// Retrieve the claims principal stored in the authorization code/refresh token.
|
||||
var result = await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
||||
|
||||
// Retrieve the user profile corresponding to the authorization code/refresh token.
|
||||
var user = await userManager.FindByIdAsync(result.Principal?.GetClaim(Claims.Subject) ?? "");
|
||||
if (user is null)
|
||||
{
|
||||
return Forbid(
|
||||
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
|
||||
properties: new AuthenticationProperties(new Dictionary<string, string?>
|
||||
{
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant,
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid."
|
||||
}));
|
||||
}
|
||||
|
||||
// Ensure the user is still allowed to sign in.
|
||||
if (!await signInManager.CanSignInAsync(user))
|
||||
{
|
||||
return Forbid(
|
||||
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
|
||||
properties: new AuthenticationProperties(new Dictionary<string, string?>
|
||||
{
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant,
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in."
|
||||
}));
|
||||
}
|
||||
|
||||
var identity = new ClaimsIdentity(result.Principal?.Claims,
|
||||
authenticationType: TokenValidationParameters.DefaultAuthenticationType,
|
||||
nameType: Claims.Name,
|
||||
roleType: Claims.Role);
|
||||
|
||||
// Override the user claims present in the principal in case they
|
||||
// changed since the authorization code/refresh token was issued.
|
||||
identity.SetClaim(Claims.Subject, await userManager.GetUserIdAsync(user))
|
||||
.SetClaim(Claims.Email, await userManager.GetEmailAsync(user))
|
||||
.SetClaim(Claims.Name, await userManager.GetUserNameAsync(user))
|
||||
.SetClaim(Claims.PreferredUsername, await userManager.GetUserNameAsync(user))
|
||||
.SetClaims(Claims.Role, [.. (await userManager.GetRolesAsync(user))]);
|
||||
|
||||
identity.SetDestinations(GetDestinations);
|
||||
|
||||
// Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
|
||||
return SignIn(new ClaimsPrincipal(identity), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
||||
}
|
||||
else if (request.IsClientCredentialsGrantType())
|
||||
{
|
||||
// Xử lý Client Credentials Flow
|
||||
var application = await applicationManager.FindByClientIdAsync(request.ClientId ?? "");
|
||||
if (application == null) throw new InvalidOperationException("The application details cannot be found in the database.");
|
||||
|
||||
// Create the claims-based identity that will be used by OpenIddict to generate tokens.
|
||||
var identity = new ClaimsIdentity(
|
||||
authenticationType: TokenValidationParameters.DefaultAuthenticationType,
|
||||
nameType: Claims.Name,
|
||||
roleType: Claims.Role);
|
||||
|
||||
// Add the claims that will be persisted in the tokens (use the client_id as the subject identifier).
|
||||
identity.SetClaim(Claims.Subject, await applicationManager.GetClientIdAsync(application));
|
||||
identity.SetClaim(Claims.Name, await applicationManager.GetDisplayNameAsync(application));
|
||||
|
||||
// Note: In the original OAuth 2.0 specification, the client credentials grant
|
||||
// doesn't return an identity token, which is an OpenID Connect concept.
|
||||
//
|
||||
// As a non-standardized extension, OpenIddict allows returning an id_token
|
||||
// to convey information about the client application when the "openid" scope
|
||||
// is granted (i.e specified when calling principal.SetScopes()). When the "openid"
|
||||
// scope is not explicitly set, no identity token is returned to the client application.
|
||||
|
||||
// Set the list of scopes granted to the client application in access_token.
|
||||
identity.SetScopes(request.GetScopes());
|
||||
identity.SetResources(await scopeManager.ListResourcesAsync(identity.GetScopes()).ToListAsync());
|
||||
identity.SetDestinations(GetDestinations);
|
||||
|
||||
return SignIn(new ClaimsPrincipal(identity), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("The specified grant type is not supported.");
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetDestinations(Claim claim)
|
||||
{
|
||||
// Note: by default, claims are NOT automatically included in the access and identity tokens.
|
||||
// To allow OpenIddict to serialize them, you must attach them a destination, that specifies
|
||||
// whether they should be included in access tokens, in identity tokens or in both.
|
||||
|
||||
switch (claim.Type)
|
||||
{
|
||||
case Claims.Name or Claims.PreferredUsername:
|
||||
yield return Destinations.AccessToken;
|
||||
|
||||
if (claim.Subject?.HasScope(Scopes.Profile) ?? false)
|
||||
yield return Destinations.IdentityToken;
|
||||
|
||||
yield break;
|
||||
|
||||
case Claims.Email:
|
||||
yield return Destinations.AccessToken;
|
||||
|
||||
if (claim.Subject?.HasScope(Scopes.Email) ?? false)
|
||||
yield return Destinations.IdentityToken;
|
||||
|
||||
yield break;
|
||||
|
||||
case Claims.Role:
|
||||
yield return Destinations.AccessToken;
|
||||
|
||||
if (claim.Subject?.HasScope(Scopes.Roles) ?? false)
|
||||
yield return Destinations.IdentityToken;
|
||||
|
||||
yield break;
|
||||
|
||||
// Never include the security stamp in the access and identity tokens, as it's a secret value.
|
||||
case "AspNet.Identity.SecurityStamp": yield break;
|
||||
|
||||
default:
|
||||
yield return Destinations.AccessToken;
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace RobotNet.IdentityServer.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[AllowAnonymous]
|
||||
public class IdentityServerLoggerController(ILogger<IdentityServerLoggerController> Logger) : ControllerBase
|
||||
{
|
||||
private readonly string LoggerDirectory = "identityServerlogs";
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IEnumerable<string>> GetLogs([FromQuery(Name = "date")] DateTime date)
|
||||
{
|
||||
string temp = "";
|
||||
try
|
||||
{
|
||||
string fileName = $"{date:yyyy-MM-dd}.log";
|
||||
string path = Path.Combine(LoggerDirectory, fileName);
|
||||
if (!Path.GetFullPath(path).StartsWith(Path.GetFullPath(LoggerDirectory)))
|
||||
{
|
||||
Logger.LogWarning($"GetLogs: phát hiện đường dẫn không hợp lệ.");
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!System.IO.File.Exists(path))
|
||||
{
|
||||
Logger.LogWarning($"GetLogs: không tìm thấy file log của ngày {date.ToShortDateString()} - {path}.");
|
||||
return [];
|
||||
}
|
||||
|
||||
temp = Path.Combine(LoggerDirectory, $"{Guid.NewGuid()}.log");
|
||||
System.IO.File.Copy(path, temp);
|
||||
|
||||
return await System.IO.File.ReadAllLinesAsync(temp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning($"GetLogs: Hệ thống có lỗi xảy ra - {ex.Message}");
|
||||
return [];
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (System.IO.File.Exists(temp)) System.IO.File.Delete(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
63
RobotNet.IdentityServer/Controllers/UserinfoController.cs
Normal file
63
RobotNet.IdentityServer/Controllers/UserinfoController.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using OpenIddict.Abstractions;
|
||||
using OpenIddict.Server.AspNetCore;
|
||||
using RobotNet.IdentityServer.Data;
|
||||
using static OpenIddict.Abstractions.OpenIddictConstants;
|
||||
|
||||
namespace RobotNet.IdentityServer.Controllers;
|
||||
|
||||
[EnableCors("RequestAuthorize")]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class UserinfoController(UserManager<ApplicationUser> userManager) : ControllerBase
|
||||
{// GET: /api/userinfo
|
||||
[Authorize(AuthenticationSchemes = OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)]
|
||||
[HttpGet(""), HttpPost(""), Produces("application/json")]
|
||||
public async Task<IActionResult> Userinfo()
|
||||
{
|
||||
var user = await userManager.FindByIdAsync(User.GetClaim(Claims.Subject) ?? "");
|
||||
if (user == null)
|
||||
{
|
||||
return Challenge(
|
||||
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
|
||||
properties: new AuthenticationProperties(new Dictionary<string, string?>
|
||||
{
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidToken,
|
||||
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
|
||||
"The specified access token is bound to an account that no longer exists."
|
||||
}));
|
||||
}
|
||||
|
||||
var claims = new Dictionary<string, object>(StringComparer.Ordinal)
|
||||
{
|
||||
// Note: the "sub" claim is a mandatory claim and must be included in the JSON response.
|
||||
[Claims.Subject] = await userManager.GetUserIdAsync(user)
|
||||
};
|
||||
|
||||
if (User.HasScope(Scopes.Email))
|
||||
{
|
||||
claims[Claims.Email] = await userManager.GetEmailAsync(user) ?? "";
|
||||
claims[Claims.EmailVerified] = await userManager.IsEmailConfirmedAsync(user);
|
||||
}
|
||||
|
||||
if (User.HasScope(Scopes.Phone))
|
||||
{
|
||||
claims[Claims.PhoneNumber] = await userManager.GetPhoneNumberAsync(user) ?? "";
|
||||
claims[Claims.PhoneNumberVerified] = await userManager.IsPhoneNumberConfirmedAsync(user);
|
||||
}
|
||||
|
||||
if (User.HasScope(Scopes.Roles))
|
||||
{
|
||||
claims[Claims.Role] = await userManager.GetRolesAsync(user);
|
||||
}
|
||||
|
||||
// Note: the complete list of standard claims supported by the OpenID Connect specification
|
||||
// can be found here: http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
|
||||
|
||||
return Ok(claims);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user