我已经实施了一个解决方案,该解决方案使我可以防止同一帐户出现多个用户会话。
为此,我在ConfigureServices
方法内添加了以下配置:
services.AddIdentity<User, IdentityRole>()
.AddEntityFrameworkStores<SoccerForecastContext>()
.AddDefaultTokenProviders();
var defaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddRequirements(new ValidSessionRequirement())
.Build();
services.AddAuthorization(options =>
{
options.DefaultPolicy = defaultPolicy;
});
services.AddScoped<IUserClaimsPrincipalFactory<User>, ApplicationClaimsPrincipalFactory>();
services.AddTransient<IAuthorizationHandler, ValidSessionHandler>();
本质上,管道将为每个请求调用
public class ApplicationClaimsPrincipalFactory : UserClaimsPrincipalFactory<User>
{
private readonly UserManager<User> _userManager;
public ApplicationClaimsPrincipalFactory(UserManager<User> userManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, optionsAccessor)
{
_userManager = userManager;
}
public async override Task<ClaimsPrincipal> CreateAsync(User user)
{
var claims = await _userManager.GetClaimsAsync(user);
var session = claims.Where(e => e.Type == "session");
await _userManager.RemoveClaimsAsync(user, session);
await _userManager.AddClaimAsync(user, new Claim("session", Guid.NewGuid().ToString()));
var principal = await base.CreateAsync(user);
return principal;
}
}
类ValidSessionRequirement
的简单继承是:
public class ValidSessionRequirement : IAuthorizationRequirement
{
}
现在我是否调用此方法:
[HttpGet]
[Authorize(Roles = "Customer, Admin, SuperAdmin")]
public async Task<IActionResult> Profile()
{
我得到:AccessDenied
,但用户扮演SuperAdmin
的角色,如果我按预期删除所有工作之上的逻辑,有什么想法吗?
答案 0 :(得分:1)
调用Authorize
时,无论您对方法应用什么角色,都将调用ValidSessionHandler
,因为它是默认策略。您可以添加检查以跳过ValidSessionHanlder
中的某些角色。下面的代码将跳过Admin
和SuperAdmin
的会话检查。
public class ValidSessionHandler : AuthorizationHandler<ValidSessionRequirement>
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
public ValidSessionHandler(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
{
_userManager = userManager ?? throw new ArgumentNullException(nameof(userManager));
_signInManager = signInManager ?? throw new ArgumentNullException(nameof(signInManager));
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ValidSessionRequirement requirement)
{
// if the user isn't authenticated then no need to check session
if (!context.User.Identity.IsAuthenticated)
return;
// get the user and session claim
var user = await _userManager.GetUserAsync(context.User);
var claims = await _userManager.GetClaimsAsync(user);
// get roles and skip check if Admin or SuperAdmin
var roles = await _userManager.GetRolesAsync(user);
foreach(var role in roles)
{
if(role == "Admin" || role == "SuperAdmin")
{
context.Succeed(requirement);
return;
}
}
var serverSession = claims.First(e => e.Type == "session");
var clientSession = context.User.FindFirst("session");
// if the client session matches the server session then the user is authorized
if (serverSession?.Value == clientSession?.Value)
{
context.Succeed(requirement);
}
return;
}
}
答案 1 :(得分:0)
这是配置方法,适用于基于策略的授权。
在void outchar(int c)
类中配置策略
Startup
在您的public void ConfigureServices(IServiceCollection services)
{
// ...
// Configure security policies
services.AddAuthorization(options =>
{
options.AddPolicy("SuperAdmins", policy => policy.RequireRole("SuperAdmin"));
options.AddPolicy("Admins", policy => policy.RequireRole("Admin", "SuperAdmin"));
options.AddPolicy("Customers", policy => policy.RequireRole("Customer", "Admin", "SuperAdmin"));
});
// ...
services.AddScoped<IUserClaimsPrincipalFactory<User>, MyUserClaimsFactory>();
// ...
}
中,您可以添加自定义声明,如下所示:
UserClaimsPrincipalFactory
在您的控制器授权属性中,应使用protected override async Task<ClaimsIdentity> GenerateClaimsAsync(User user)
{
var userId = user.Id;
user = await UserManager.Users.SingleAsync(u => u.Id == userId);
// Add role claims
var identity = await base.GenerateClaimsAsync(user);
// Add custom claims for application user properties we want to store in claims (in cookies) which allows to get common values on UI without DB hit)
identity.AddClaim(new Claim(ClaimTypes.GivenName, user.FirstName ?? ""));
identity.AddClaim(new Claim(ClaimTypes.Surname, user.LastName ?? ""));
// Add your session or any other claims here if needed
return identity;
}
名称,如下所示:
Policy