get more claims
This commit is contained in:
parent
43b289886e
commit
3df1c1b14d
7 changed files with 135 additions and 169 deletions
|
|
@ -13,7 +13,8 @@ using System.Diagnostics;
|
|||
|
||||
namespace Yavsc.WebApi.Controllers
|
||||
{
|
||||
[Authorize("ApiScope"),Route("~/api/account")]
|
||||
[Route("~/api/account")]
|
||||
[Authorize("ApiScope")]
|
||||
public class ApiAccountController : Controller
|
||||
{
|
||||
private UserManager<ApplicationUser> _userManager;
|
||||
|
|
@ -22,9 +23,12 @@ namespace Yavsc.WebApi.Controllers
|
|||
private readonly ILogger _logger;
|
||||
|
||||
public ApiAccountController(UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager, ILoggerFactory loggerFactory, ApplicationDbContext dbContext)
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
RoleManager<IdentityRole> roleManager,
|
||||
ILoggerFactory loggerFactory, ApplicationDbContext dbContext)
|
||||
{
|
||||
UserManager = userManager;
|
||||
this.roleManager = roleManager;
|
||||
_signInManager = signInManager;
|
||||
_logger = loggerFactory.CreateLogger("ApiAuth");
|
||||
_dbContext = dbContext;
|
||||
|
|
@ -42,9 +46,11 @@ namespace Yavsc.WebApi.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
private readonly RoleManager<IdentityRole> roleManager;
|
||||
|
||||
// POST api/Account/ChangePassword
|
||||
|
||||
public async Task<IActionResult> ChangePassword(ChangePasswordBindingModel model)
|
||||
|
||||
public async Task<IActionResult> ChangePassword(ChangePasswordBindingModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
|
|
@ -122,14 +128,14 @@ namespace Yavsc.WebApi.Controllers
|
|||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
[HttpGet("~/api/otherme")]
|
||||
public async Task<IActionResult> Me ()
|
||||
[HttpGet("me")]
|
||||
public async Task<IActionResult> Me()
|
||||
{
|
||||
if (User==null)
|
||||
return new BadRequestObjectResult(
|
||||
new { error = "user not found" });
|
||||
var uid = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
var uuid = User.GetUserId();
|
||||
var uid = User.GetUserId();
|
||||
|
||||
var userData = await _dbContext.Users
|
||||
.Include(u=>u.PostalAddress)
|
||||
.Include(u=>u.AccountBalance)
|
||||
|
|
@ -139,9 +145,9 @@ namespace Yavsc.WebApi.Controllers
|
|||
userData.Avatar ,
|
||||
userData.PostalAddress, userData.DedicatedGoogleCalendar );
|
||||
|
||||
var userRoles = _dbContext.UserRoles.Where(u=>u.UserId == uid).ToArray();
|
||||
var userRoles = _dbContext.UserRoles.Where(u=>u.UserId == uid).Select(r => r.RoleId).ToArray();
|
||||
|
||||
IdentityRole [] roles = _dbContext.Roles.Where(r=>userRoles.Any(ur=>ur.RoleId==r.Id)).ToArray();
|
||||
IdentityRole [] roles = _dbContext.Roles.Where(r=>userRoles.Contains(r.Id)).ToArray();
|
||||
|
||||
user.Roles = roles.Select(r=>r.Name).ToArray();
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ public static class Config
|
|||
AllowedScopes = {
|
||||
IdentityServerConstants.StandardScopes.OpenId,
|
||||
IdentityServerConstants.StandardScopes.Profile,
|
||||
IdentityServerConstants.StandardScopes.Email }
|
||||
IdentityServerConstants.StandardScopes.Email,
|
||||
"scope2" }
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -178,34 +178,11 @@ internal static class HostingExtensions
|
|||
services.AddDbContext<ApplicationDbContext>(options =>
|
||||
options.UseNpgsql(builder.Configuration.GetConnectionString("Default")));
|
||||
|
||||
services
|
||||
.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy("ApiScope", policy =>
|
||||
{
|
||||
policy
|
||||
.RequireAuthenticatedUser()
|
||||
.RequireClaim("scope", "api1");
|
||||
});
|
||||
});
|
||||
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>()
|
||||
.AddDefaultTokenProviders();
|
||||
|
||||
|
||||
var identityServerBuilder = services.AddIdentityServer(options =>
|
||||
{
|
||||
options.Events.RaiseErrorEvents = true;
|
||||
options.Events.RaiseInformationEvents = true;
|
||||
options.Events.RaiseFailureEvents = true;
|
||||
options.Events.RaiseSuccessEvents = true;
|
||||
|
||||
// see https://docs.duendesoftware.com/identityserver/v6/fundamentals/resources/
|
||||
options.EmitStaticAudienceClaim = true;
|
||||
options.EmitScopesAsSpaceDelimitedStringInJwt = true;
|
||||
options.Endpoints.EnableUserInfoEndpoint = true;
|
||||
})
|
||||
var identityServerBuilder = services.AddIdentityServer()
|
||||
.AddInMemoryIdentityResources(Config.IdentityResources)
|
||||
.AddInMemoryClients(Config.Clients)
|
||||
.AddInMemoryApiScopes(Config.ApiScopes)
|
||||
|
|
@ -230,13 +207,7 @@ services
|
|||
// TODO .AddServerSideSessionStore<YavscServerSideSessionStore>()
|
||||
|
||||
|
||||
var authenticationBuilder = services.AddAuthentication("Bearer")
|
||||
.AddJwtBearer("Bearer", options =>
|
||||
{
|
||||
options.Authority = "https://localhost:5001";
|
||||
options.TokenValidationParameters =
|
||||
new() { ValidateAudience = false };
|
||||
});
|
||||
var authenticationBuilder = services.AddAuthentication();
|
||||
|
||||
authenticationBuilder.AddGoogle(options =>
|
||||
{
|
||||
|
|
@ -326,7 +297,7 @@ services
|
|||
_ = services.AddTransient<IBillingService, BillingService>();
|
||||
_ = services.AddTransient<IDataStore, FileDataStore>((sp) => new FileDataStore("googledatastore", false));
|
||||
_ = services.AddTransient<ICalendarManager, CalendarManager>();
|
||||
services.AddTransient<IProfileService, ProfileService>();
|
||||
//services.AddTransient<IProfileService, ProfileService>();
|
||||
|
||||
|
||||
// TODO for SMS: services.AddTransient<ISmsSender, AuthMessageSender>();
|
||||
|
|
@ -343,8 +314,15 @@ services
|
|||
{
|
||||
options.AddPolicy("ApiScope", policy =>
|
||||
{
|
||||
policy.RequireAuthenticatedUser();
|
||||
policy.RequireAuthenticatedUser()
|
||||
.RequireClaim("scope", "scope2");
|
||||
});
|
||||
options.AddPolicy("Performer", policy =>
|
||||
{
|
||||
policy
|
||||
.RequireAuthenticatedUser()
|
||||
.RequireClaim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "Performer");
|
||||
});
|
||||
options.AddPolicy("AdministratorOnly", policy =>
|
||||
{
|
||||
_ = policy.RequireClaim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", Constants.AdminGroupName);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System.Security.Claims;
|
|||
using IdentityModel;
|
||||
using IdentityServer8.Models;
|
||||
using IdentityServer8.Services;
|
||||
using IdentityServer8.Stores;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Yavsc.Models;
|
||||
|
||||
|
|
@ -10,38 +11,65 @@ namespace Yavsc.Services
|
|||
public class ProfileService : IProfileService
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly RoleManager<IdentityRole> _roleManager;
|
||||
public ProfileService(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
RoleManager<IdentityRole> roleManager)
|
||||
UserManager<ApplicationUser> userManager)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_roleManager = roleManager;
|
||||
}
|
||||
|
||||
public async Task<List<Claim>> GetClaimsFromUserAsync(ApplicationUser user)
|
||||
public async Task<List<Claim>> GetClaimsFromUserAsync(
|
||||
ProfileDataRequestContext context,
|
||||
ApplicationUser user)
|
||||
{
|
||||
|
||||
var allowedScopes = context.Client.AllowedScopes
|
||||
.Where(s => s != JwtClaimTypes.Subject)
|
||||
.ToList();
|
||||
if (allowedScopes.Contains("profile"))
|
||||
{
|
||||
allowedScopes.Remove("profile");
|
||||
allowedScopes.Add(JwtClaimTypes.Name);
|
||||
allowedScopes.Add(JwtClaimTypes.FamilyName);
|
||||
allowedScopes.Add(JwtClaimTypes.Email);
|
||||
allowedScopes.Add(JwtClaimTypes.PreferredUserName);
|
||||
allowedScopes.Add("http://schemas.microsoft.com/ws/2008/06/identity/claims/role");
|
||||
}
|
||||
|
||||
var claims = new List<Claim> {
|
||||
new Claim(JwtClaimTypes.Subject,user.Id.ToString()),
|
||||
new Claim(JwtClaimTypes.PreferredUserName,user.UserName)
|
||||
};
|
||||
|
||||
var role = await _userManager.GetRolesAsync(user);
|
||||
role.ToList().ForEach(f =>
|
||||
foreach (var subClaim in context.Subject.Claims)
|
||||
{
|
||||
claims.Add(new Claim(JwtClaimTypes.Role, f));
|
||||
});
|
||||
if (allowedScopes.Contains(subClaim.Type))
|
||||
claims.Add(subClaim);
|
||||
}
|
||||
|
||||
AddClaims(allowedScopes, claims, JwtClaimTypes.Email, user.Email);
|
||||
AddClaims(allowedScopes, claims, JwtClaimTypes.PreferredUserName, user.FullName);
|
||||
|
||||
foreach (var scope in context.Client.AllowedScopes)
|
||||
{
|
||||
claims.Add(new Claim("scope", scope));
|
||||
}
|
||||
|
||||
return claims;
|
||||
}
|
||||
|
||||
private static void AddClaims(List<string> allowedScopes, List<Claim> claims,
|
||||
string claimType, string claimValue
|
||||
)
|
||||
{
|
||||
if (allowedScopes.Contains(claimType))
|
||||
if (!claims.Any(c => c.Type == claimType))
|
||||
claims.Add(new Claim(claimType, claimValue));
|
||||
}
|
||||
|
||||
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
|
||||
{
|
||||
var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
|
||||
var user = await _userManager.FindByIdAsync(subjectId);
|
||||
context.IssuedClaims = await GetClaimsFromUserAsync(user);
|
||||
context.IssuedClaims = await GetClaimsFromUserAsync(context, user);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue