Externl Login
This commit is contained in:
5
.vscode/launch.json
vendored
5
.vscode/launch.json
vendored
@ -109,6 +109,11 @@
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
},
|
||||
"presentation": {
|
||||
"hidden": false,
|
||||
"group": "run",
|
||||
"order": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ namespace Yavsc.Helpers
|
||||
|
||||
public static string GetUserName(this ClaimsPrincipal user)
|
||||
{
|
||||
return user.FindFirstValue(ClaimTypes.Name);
|
||||
return user.FindFirstValue("name");
|
||||
}
|
||||
|
||||
public static bool IsSignedIn(this ClaimsPrincipal user)
|
||||
|
@ -36,6 +36,7 @@ namespace Yavsc.Models
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Yavsc.Abstract.Models.Messaging;
|
||||
using Org.BouncyCastle.Asn1.Crmf;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
|
||||
{
|
||||
@ -85,8 +86,7 @@ namespace Yavsc.Models
|
||||
}
|
||||
|
||||
builder.Entity<Activity>().Property(a => a.ParentCode).IsRequired(false);
|
||||
//builder.Entity<BlogPost>().HasOne(p => p.Author).WithMany(a => a.Posts);
|
||||
|
||||
builder.Entity<IdentityUserLogin<String>>().HasKey(i=> new { i.LoginProvider, i.UserId, i.ProviderKey });
|
||||
}
|
||||
|
||||
// this is not a failback procedure.
|
||||
@ -301,6 +301,6 @@ namespace Yavsc.Models
|
||||
public DbSet<Scope> Scopes { get; set; }
|
||||
|
||||
public DbSet<BlogSpotPublication> blogSpotPublications{ get; set; }
|
||||
|
||||
public DbSet<IdentityUserLogin<String>> AspNetUserLogins { get; set; }
|
||||
}
|
||||
}
|
||||
|
33
src/Yavsc.Server/Models/IdentityUserLogin.cs
Normal file
33
src/Yavsc.Server/Models/IdentityUserLogin.cs
Normal file
@ -0,0 +1,33 @@
|
||||
namespace Yavsc.Models.Auth
|
||||
{
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
public class YaIdentityUserLogin
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the login provider for the login (e.g. facebook, google)
|
||||
/// </summary>
|
||||
public virtual string LoginProvider { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the unique provider identifier for this login.
|
||||
/// </summary>
|
||||
public virtual string ProviderKey { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the friendly name used in a UI for this login.
|
||||
/// </summary>
|
||||
public virtual string? ProviderDisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the primary key of the user associated with this login.
|
||||
/// </summary>
|
||||
public String UserId { get; set; } = default!;
|
||||
|
||||
[ForeignKey("UserId")]
|
||||
public virtual ApplicationUser User { get; set; }
|
||||
|
||||
}
|
||||
}
|
228
src/Yavsc/Controllers/Accounting/ExternalController.cs
Normal file
228
src/Yavsc/Controllers/Accounting/ExternalController.cs
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
Copyright (c) 2024 HigginsSoft, Alexander Higgins - https://github.com/alexhiggins732/
|
||||
|
||||
Copyright (c) 2018, Brock Allen & Dominick Baier. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||
Source code and license this software can be found
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
using System.Security.Claims;
|
||||
using IdentityModel;
|
||||
using IdentityServer8;
|
||||
using IdentityServer8.Events;
|
||||
using IdentityServer8.Services;
|
||||
using IdentityServer8.Stores;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc;
|
||||
using Yavsc.Extensions;
|
||||
using Yavsc.Interfaces;
|
||||
using Yavsc.Models;
|
||||
|
||||
namespace IdentityServerHost.Quickstart.UI;
|
||||
|
||||
[SecurityHeaders]
|
||||
[AllowAnonymous]
|
||||
public class ExternalController : Controller
|
||||
{
|
||||
private readonly IIdentityServerInteractionService _interaction;
|
||||
private readonly IClientStore _clientStore;
|
||||
private readonly ILogger<ExternalController> _logger;
|
||||
private readonly IEventService _events;
|
||||
private IExternalIdentityManager _users;
|
||||
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly RoleManager<IdentityRole> _roleManager;
|
||||
private readonly ApplicationDbContext _dbContext;
|
||||
|
||||
public ExternalController(
|
||||
IIdentityServerInteractionService interaction,
|
||||
IClientStore clientStore,
|
||||
IEventService events,
|
||||
ILogger<ExternalController> logger,
|
||||
IExternalIdentityManager externalIdentityProviderManager,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
ApplicationDbContext dbContext,
|
||||
RoleManager<IdentityRole> roleManager
|
||||
)
|
||||
{
|
||||
// if the TestUserStore is not in DI, then we'll just use the global users collection
|
||||
// this is where you would plug in your own custom identity management library (e.g. ASP.NET Identity)
|
||||
_users = externalIdentityProviderManager;
|
||||
_interaction = interaction;
|
||||
_clientStore = clientStore;
|
||||
_logger = logger;
|
||||
_events = events;
|
||||
_signInManager = signInManager;
|
||||
_roleManager = roleManager;
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// initiate roundtrip to external authentication provider
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public IActionResult Challenge(string scheme, string returnUrl)
|
||||
{
|
||||
if (string.IsNullOrEmpty(returnUrl)) returnUrl = "~/";
|
||||
|
||||
// validate returnUrl - either it is a valid OIDC URL or back to a local page
|
||||
if (Url.IsLocalUrl(returnUrl) == false && _interaction.IsValidReturnUrl(returnUrl) == false)
|
||||
{
|
||||
// user might have clicked on a malicious link - should be logged
|
||||
throw new Exception("invalid return URL");
|
||||
}
|
||||
|
||||
// start challenge and roundtrip the return URL and scheme
|
||||
var props = new AuthenticationProperties
|
||||
{
|
||||
RedirectUri = Url.Action(nameof(Callback)),
|
||||
Items =
|
||||
{
|
||||
{ "returnUrl", returnUrl },
|
||||
{ "scheme", scheme },
|
||||
}
|
||||
};
|
||||
|
||||
return Challenge(props, scheme);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Post processing of external authentication
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Callback()
|
||||
{
|
||||
// read external identity from the temporary cookie
|
||||
var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
|
||||
if (result?.Succeeded != true)
|
||||
{
|
||||
throw new Exception("External authentication error");
|
||||
}
|
||||
|
||||
if (_logger.IsEnabled(LogLevel.Debug))
|
||||
{
|
||||
var externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}");
|
||||
_logger.LogDebug("External claims: {@claims}", externalClaims);
|
||||
}
|
||||
|
||||
// lookup our user and external provider info
|
||||
var (user, provider, providerUserId, claims) = await FindUserFromExternalProvider(result);
|
||||
if (user == null)
|
||||
{
|
||||
// this might be where you might initiate a custom workflow for user registration
|
||||
// in this sample we don't show how that would be done, as our sample implementation
|
||||
// simply auto-provisions new external user
|
||||
user = AutoProvisionUser(provider, providerUserId, claims);
|
||||
}
|
||||
|
||||
// this allows us to collect any additional claims or properties
|
||||
// for the specific protocols used and store them in the local auth cookie.
|
||||
// this is typically used to store data needed for signout from those protocols.
|
||||
var additionalLocalClaims = new List<Claim>();
|
||||
var localSignInProps = new AuthenticationProperties();
|
||||
ProcessLoginCallback(result, additionalLocalClaims, localSignInProps);
|
||||
|
||||
// issue authentication cookie for user
|
||||
var isuser = new IdentityServerUser(user.Id)
|
||||
{
|
||||
DisplayName = user.UserName,
|
||||
IdentityProvider = provider,
|
||||
AdditionalClaims = additionalLocalClaims
|
||||
};
|
||||
await HttpContext.SignInAsync(isuser, localSignInProps);
|
||||
//await HttpContext.SignInAsync(user, _roleManager, false, _dbContext);
|
||||
|
||||
// delete temporary cookie used during external authentication
|
||||
await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
|
||||
// retrieve return URL
|
||||
var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";
|
||||
|
||||
// check if external login is in the context of an OIDC request
|
||||
var context = await _interaction.GetAuthorizationContextAsync(returnUrl);
|
||||
await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, user.UserName, true, context?.Client.ClientId));
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
if (context.IsNativeClient())
|
||||
{
|
||||
// The client is native, so this change in how to
|
||||
// return the response is for better UX for the end user.
|
||||
return this.LoadingPage("Redirect", returnUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Redirect(returnUrl);
|
||||
}
|
||||
|
||||
private async Task<(ApplicationUser user,
|
||||
string provider,
|
||||
string providerUserId,
|
||||
IEnumerable<Claim> claims)>
|
||||
FindUserFromExternalProvider(AuthenticateResult result)
|
||||
{
|
||||
var externalUser = result.Principal;
|
||||
|
||||
// try to determine the unique id of the external user (issued by the provider)
|
||||
// the most common claim type for that are the sub claim and the NameIdentifier
|
||||
// depending on the external provider, some other claim type might be used
|
||||
var userIdClaim = externalUser.FindFirst(JwtClaimTypes.Subject) ??
|
||||
externalUser.FindFirst(ClaimTypes.NameIdentifier) ??
|
||||
throw new Exception("Unknown userid");
|
||||
|
||||
// remove the user id claim so we don't include it as an extra claim if/when we provision the user
|
||||
var claims = externalUser.Claims.ToList();
|
||||
claims.Remove(userIdClaim);
|
||||
|
||||
var provider = result.Properties.Items["scheme"];
|
||||
var providerUserId = userIdClaim.Value;
|
||||
|
||||
// find external user
|
||||
|
||||
ApplicationUser? user = await _users.FindByExternaleProviderAsync (provider, providerUserId);
|
||||
|
||||
return (user, provider, providerUserId, claims);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a new user by external id
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="providerUserId"></param>
|
||||
/// <param name="claims"></param>
|
||||
/// <returns></returns>
|
||||
private ApplicationUser AutoProvisionUser(string provider, string providerUserId, IEnumerable<Claim> claims)
|
||||
{
|
||||
var user = _users.AutoProvisionUser(provider, providerUserId, claims.ToList());
|
||||
return user;
|
||||
}
|
||||
|
||||
// if the external login is OIDC-based, there are certain things we need to preserve to make logout work
|
||||
// this will be different for WS-Fed, SAML2p or other protocols
|
||||
private void ProcessLoginCallback(AuthenticateResult externalResult, List<Claim> localClaims, AuthenticationProperties localSignInProps)
|
||||
{
|
||||
// if the external system sent a session id claim, copy it over
|
||||
// so we can use it for single sign-out
|
||||
var sid = externalResult.Principal.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.SessionId);
|
||||
if (sid != null)
|
||||
{
|
||||
localClaims.Add(new Claim(JwtClaimTypes.SessionId, sid.Value));
|
||||
}
|
||||
|
||||
// if the external provider issued an id_token, we'll keep it for signout
|
||||
var idToken = externalResult.Properties.GetTokenValue("id_token");
|
||||
if (idToken != null)
|
||||
{
|
||||
localSignInProps.StoreTokens(new[] { new AuthenticationToken { Name = "id_token", Value = idToken } });
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright (c) 2024 HigginsSoft, Alexander Higgins - https://github.com/alexhiggins732/
|
||||
|
||||
Copyright (c) 2018, Brock Allen & Dominick Baier. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
|
||||
Source code and license this software can be found
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
*/
|
||||
|
||||
using System.Security.Claims;
|
||||
using Yavsc.Models;
|
||||
|
||||
namespace Yavsc.Interfaces;
|
||||
|
||||
public interface IExternalIdentityManager
|
||||
{
|
||||
ApplicationUser AutoProvisionUser(string provider, string providerUserId, List<Claim> claims);
|
||||
Task<ApplicationUser?> FindByExternaleProviderAsync(string provider, string providerUserId);
|
||||
}
|
@ -36,6 +36,7 @@ using Microsoft.IdentityModel.Protocols.Configuration;
|
||||
using IdentityModel;
|
||||
using System.Security.Claims;
|
||||
using IdentityServer8.Security;
|
||||
using Yavsc.Interfaces;
|
||||
|
||||
namespace Yavsc.Extensions;
|
||||
|
||||
@ -112,6 +113,7 @@ public static class HostingExtensions
|
||||
AddYavscPolicies(services);
|
||||
|
||||
services.AddScoped<IAuthorizationHandler, PermissionHandler>();
|
||||
services.AddTransient<IExternalIdentityManager, ExternalIdentityManager>();
|
||||
|
||||
|
||||
AddAuthentication(builder);
|
||||
@ -215,11 +217,12 @@ public static class HostingExtensions
|
||||
// set the redirect URI to https://localhost:5001/signin-google
|
||||
options.ClientId = googleClientId;
|
||||
options.ClientSecret = googleClientSecret;
|
||||
|
||||
});
|
||||
}
|
||||
private static IIdentityServerBuilder AddIdentityServer(WebApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.AddTransient<IProfileService,ProfileService>();
|
||||
//builder.Services.AddTransient<IProfileService,ProfileService>();
|
||||
var identityServerBuilder = builder.Services.AddIdentityServer(options =>
|
||||
{
|
||||
options.Events.RaiseErrorEvents = true;
|
||||
@ -234,7 +237,7 @@ public static class HostingExtensions
|
||||
.AddInMemoryIdentityResources(Config.IdentityResources)
|
||||
.AddInMemoryClients(Config.Clients)
|
||||
.AddInMemoryApiScopes(Config.ApiScopes)
|
||||
.AddProfileService<ProfileService>()
|
||||
// .AddProfileService<ProfileService>()
|
||||
.AddAspNetIdentity<ApplicationUser>()
|
||||
;
|
||||
if (builder.Environment.IsDevelopment())
|
||||
|
28
src/Yavsc/Services/ExternalIdentityManager.cs
Normal file
28
src/Yavsc/Services/ExternalIdentityManager.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Yavsc.Interfaces;
|
||||
using Yavsc.Models;
|
||||
|
||||
public class ExternalIdentityManager : IExternalIdentityManager
|
||||
{
|
||||
private ApplicationDbContext _applicationDbContext;
|
||||
|
||||
public ExternalIdentityManager(ApplicationDbContext applicationDbContext)
|
||||
{
|
||||
_applicationDbContext = applicationDbContext;
|
||||
}
|
||||
public ApplicationUser AutoProvisionUser(string provider, string providerUserId, List<Claim> claims)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<ApplicationUser?> FindByExternaleProviderAsync(string provider, string providerUserId)
|
||||
{
|
||||
var user = await _applicationDbContext.AspNetUserLogins
|
||||
.FirstOrDefaultAsync(
|
||||
i => (i.LoginProvider == provider) && (i.ProviderKey == providerUserId)
|
||||
);
|
||||
if (user == null) return null;
|
||||
return await _applicationDbContext.Users.FirstOrDefaultAsync(u=>u.Id == user.UserId);
|
||||
}
|
||||
}
|
@ -2,17 +2,10 @@
|
||||
@inject SignInManager<ApplicationUser> SignInManager
|
||||
@inject UserManager<ApplicationUser> UserManager
|
||||
|
||||
@{
|
||||
#nullable enable
|
||||
string? name = null;
|
||||
if (Context.User!=null)
|
||||
{
|
||||
name = Context.User.GetUserName();
|
||||
}
|
||||
}
|
||||
|
||||
@if (name!=null)
|
||||
@if (Context.User?.Identity?.IsAuthenticated ?? false)
|
||||
{
|
||||
string userName = User.GetUserName();
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown04" data-bs-toggle="dropdown" aria-expanded="false">Plateforme</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdown04">
|
||||
@ -37,7 +30,7 @@
|
||||
</ul>
|
||||
</li>}
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown04" data-bs-toggle="dropdown" aria-expanded="false">Hello @UserManager.GetUserName(User)!</a>
|
||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown04" data-bs-toggle="dropdown" aria-expanded="false">Hello @userName!</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a class="dropdown-item" asp-controller="Manage" asp-action="Index" title="Manage">
|
||||
@ -61,3 +54,5 @@ else
|
||||
<a class="nav-link" asp-controller="Account" asp-action="Login" asp-route-ReturnUrl="~/" >Login</a>
|
||||
</li>
|
||||
}
|
||||
using IdentityServer8.Extensions;
|
||||
#line default
|
||||
|
@ -17,30 +17,31 @@
|
||||
<PackageReference Include="HigginsSoft.IdentityServer8.AspNetIdentity" Version="8.0.5-preview-net9" />
|
||||
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.6">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.7">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.6">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.7" />
|
||||
<PackageReference Include="Google.Apis.Compute.v1" Version="1.70.0.3829" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor" Version="2.3.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0" />
|
||||
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.6" />
|
||||
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Antiforgery" Version="2.3.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.3" />
|
||||
<PackageReference Include="AsciiDocNet" Version="1.0.0-alpha6" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.10" />
|
||||
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.7" />
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Yavsc.Server/Yavsc.Server.csproj" />
|
||||
|
@ -13,9 +13,7 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
|
||||
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
|
||||
|
||||
|
||||
JwtSecurityTokenHandler.DefaultMapInboundClaims = true;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@ -38,13 +36,11 @@ builder.Services
|
||||
options.Scope.Add("profile");
|
||||
options.Scope.Add("scope2");
|
||||
options.MapInboundClaims = true;
|
||||
options.ClaimActions.MapUniqueJsonKey("preferred_username","preferred_username");
|
||||
options.ClaimActions.MapUniqueJsonKey("preferred_username", "preferred_username");
|
||||
options.ClaimActions.MapUniqueJsonKey("gender", "gender");
|
||||
|
||||
options.SaveTokens = true;
|
||||
});
|
||||
|
||||
|
||||
using (var app = builder.Build())
|
||||
{
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Yavsc.Abstract\Yavsc.Abstract.csproj" />
|
||||
<PackageReference Include="IdentityModel.AspNetCore" Version="4.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
Reference in New Issue
Block a user