UserManager
class as GetUserName
, SetUserName
and ChangePassword
ChangePassword
lead to calls of the same type from UserStore.IUserLoginStore
IUserRoleStore
IUserClaimStore
IUserPasswordStore
IUserSecurityStampStore
IUserEmailStore
IUserLockoutStore
IUserPhoneNumberStore
IQueryableUserStore
IUserTwoFactorStore
IUserStore
IUserStore
and IUserPasswordStore
. public void ConfigureServices(IServiceCollection services) { // more here // Identity services.AddIdentity<ApplicationUser, IdentityRole>() // UserStore/RoleStore EF .AddEntityFrameworkStores<ApplicationDbContext>() // .AddDefaultTokenProviders(); // more here }
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { // more here app.UseIdentity(); // Cookie Auth Middleware // more here }
services.AddScoped<IPasswordHasher<User>, MyPasswordHasher>(); services.AddIdentity<ApplicationUser, IdentityRole>(options => { options.Password.RequireDigit = true; options.Password.RequiredLength = 8; options.SignIn.RequireConfirmedEmail = true; options.ClaimsIdentity.RoleClaimType = "MyRoleClaimType"; }) .AddUserStore<MyStore>() .AddRoleStore<MyRoleStore>() .AddUserValidator<MyUserValidator>() .AddDefaultTokenProviders();
IPasswordHasher
, we have no extension method. In this case, to register, we need to register the password hash service before Identity does it.Action, .
, . UserManager , , , , . , IdentityOptions
.
Identity: Identity 2 , NameNormilized
EmailNormalized
. UserManager
, IUserStore
. , UPPER()
. , , .
, Identity . / ASP.NET 5. , , , . : , MembershipProvider
(.NET 2.0): - , UserManager
NotSupportedException .
Action, .
, . UserManager
, , , , . , IdentityOptions
.
Identity: Identity 2 , NameNormilized
EmailNormalized
. UserManager
, IUserStore
. , UPPER()
. , , .
, Identity . / ASP.NET 5. , , , . : , MembershipProvider
(.NET 2.0): - , UserManager
NotSupportedException .
Configure
method, we call the app.UseIdentity()
extension method. Under the hood of this method, middleware is connected, setting up the authentication cookie pipeline: var options = app.ApplicationServices.GetRequiredService<IOptions<IdentityOptions>>().Value; app.UseCookieAuthentication(options.Cookies.ExternalCookie); app.UseCookieAuthentication(options.Cookies.TwoFactorRememberMeCookie); app.UseCookieAuthentication(options.Cookies.TwoFactorUserIdCookie); app.UseCookieAuthentication(options.Cookies.ApplicationCookie);
UseCookieAuthentication
connects middleware: app.UseMiddleware<CookieAuthenticationMiddleware>(options);
AuthenticationManager
class, which hangs on the HttpContext
. Suppose we do not want to use Identity to manage our users, but prefer to do it ourselves: // SignOut var authenticationDescriptions = HttpContext.Authentication.GetAuthenticationSchemes(); foreach (var authenticationDescription in authenticationDescriptions) { HttpContext.Authentication.SignOutAsync(authenticationDescription.AuthenticationScheme); } // ASP.NET ClaimsIdentity // ClaimsIdentity var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, "123"), new Claim(ClaimsIdentity.DefaultNameClaimType, "MyUserName"), new Claim(ClaimTypes.Role, "Administrators"), new Claim("Lastname", "MyLastName"), new Claim("email", "bob@smith.com") }; var id = new ClaimsIdentity(claims, "MyCookiesScheme", ClaimsIdentity.DefaultNameClaimType, ClaimTypes.Role); var principal = new ClaimsPrincipal(id); // ClaimsPrincipal HttpContext.Authentication.SignInAsync("MyCookiesScheme", new ClaimsPrincipal(id));
SignInManager
from ASP.NET Identity also operates in approximately the same way. During authentication, we need to indicate with what kind of authentication scheme we log in the user. Based on this parameter, the AuthenticationManager
determines which middleware to interact with.[Authorize]
attribute and checks of the type user.IsInRole
. When security requirements change, making changes to the application is an extremely time-consuming and error-prone process. It is necessary to find all the places where this or that role is used, or it is necessary to find and change all the places where a particular function of the application is accessed. Those. authorization code is blurred by application.[Authorize]
attribute now accepts not a list of roles, but “policies”.[Authorize(Roles=””)]
supported for backward compatibility) services.AddAuthorization(options => { options.AddPolicy("SuperAdministrationPolicy", policy => { policy.RequireRole("Admins"); policy.RequireClaim("adminlevel", "Level1", "Level2"); }); options.AddPolicy("RegularAdministrationPolicy", policy => { policy.RequireRole("Admins"); }); });
AuthorizationPolicy
contains a set of Requirements
(requirements). By default, we have Requirements
for checking roles, brands and usernames. You can also describe Requirement
as a separate class: public class AdminLevelRequirement : AuthorizationHandler<AdminLevelRequirement>, IAuthorizationRequirement { private readonly string _adminLevel; public AdminLevelRequirement(string adminLevel) { _adminLevel = adminLevel; } protected override void Handle(AuthorizationContext context, AdminLevelRequirement requirement) { var user = context.User; if (user.IsInRole("Admins") && user.HasClaim("adminlevel", _adminLevel)) { context.Succeed(requirement); } } } // requirement options.AddPolicy("AdminLevel1Policy", policy => { policy.AddRequirements(new AdminLevelRequirement("Level1")); });
AuthorizationHandler<>
and IAuthorizationRequirement
, but this is not necessary. Here, the AdminLevelRequirement
describes both the request and the request handler. In the simple case, this is quite a suitable solution. But if you need more flexibility, then we can separate the requirements and processors. The class of our requirement (Requirement) must be inherited from the IAuthorizationRequirement
(marker interface), and it will carry only the description of the parameters of the requirement. For example, the administrator level, his access level. In turn, the classes for processing requests inherit AuthorizationHandler<>
and contain only methods Handle()
. // public class AdminLevelRequirement : IAuthorizationRequirement { public string AdminLevel { get; } public AdminLevelRequirement(string adminLevel) { AdminLevel = adminLevel; } } // public class AdminLevelRequirementHandler : AuthorizationHandler<AdminLevelRequirement> { protected override void Handle(AuthorizationContext context, AdminLevelRequirement requirement) { var user = context.User; if (user.IsInRole("Admins") && user.HasClaim("adminlevel", requirement.AdminLevel)) { context.Succeed(requirement); } } } // policy.AddRequirements(new AdminLevelRequirement("Level1")); // services.AddInstance<IAuthorizationHandler>(new AdminLevelRequirementHandler());
AuthorizationContext.Suceed()
or AuthorizationContext.Fail()
. If we have described several handlers for one requirement, we can perform them on the principle of OR or AND. For execution in the OR style, handlers can only return Succeed()
. If you need AND processing logic, then we can use the Fail()
return. Those. if Fail()
never called in the handlers, then if any of the handlers are successfully tested, the user will be granted access. [Authorize("PoliyName")] public IActionResult ActionName()
// public class HomeController : Controller { private readonly IAuthorizationService _authorizationService; public HomeController(IAuthorizationService authorizationService) { _authorizationService = authorizationService; } }
if (await _authorizationService.AuthorizeAsync(User, "MyPolicy"))
public class TenantAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Tenant> { protected override void Handle(AuthorizationContext context, OperationAuthorizationRequirement requirement, Tenant resource) { if (requirement.Name == "Update") { if (!context.User.HasClaim("adminlevel", "Level1")) { context.Fail(); return; } if (!context.User.HasClaim("region", resource.Region)) { context.Fail(); return; } context.Succeed(requirement); return; } context.Fail(); } }
OperationAuthorizationRequirement
is the default requirement class that has only the Name property. This class can be used for simple scripts and user access checks for named operations, for example, Read
, Update
, Delete
and so on. Of course, in this case we can also describe our own classes of requirements.Source: https://habr.com/ru/post/273753/
All Articles