how to override a method of Microsoft Identity? - c#

I am newbie in C# and .Net
I am using a getter of SignInManager in one of my controllers like this:
public CustomSignInManager SignInManager
{
get
{
return HttpContext.GetOwinContext().Get<CustomSignInManager >();
}
}
and the CustomSignInManager class is like this:
public class OnlineSmSignInManager : SignInManager<User, int>
{
public OnlineSmSignInManager(OnlineSmUserManager userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{ }
}
there is a method in Identity's SignInManager class like this:
public virtual async Task<token> SendTwoFactorCodeAsync(string provider)
{
TKey userId = await this.GetVerifiedUserIdAsync().WithCurrentCulture<TKey>();
if ((object) userId == null)
return false;
string token = await this.UserManager.GenerateTwoFactorTokenAsync(userId, provider).WithCurrentCulture<string>();
IdentityResult identityResult = await this.UserManager.NotifyTwoFactorTokenAsync(userId, provider, token).WithCurrentCulture<IdentityResult>();
return token;
}
how can I override it to be like this:

In C# virtual members can be overriden by replacing the word virtual in the derived class:
public override async Task<bool> SendTwoFactorCodeAsync(string provider)
{
TKey userId = await this.GetVerifiedUserIdAsync().WithCurrentCulture<TKey>();
if ((object) userId == null)
return false;
string token = await this.UserManager.GenerateTwoFactorTokenAsync(userId, provider).WithCurrentCulture<string>();
IdentityResult identityResult = await this.UserManager.NotifyTwoFactorTokenAsync(userId, provider, token).WithCurrentCulture<IdentityResult>();
return true;
}
That goes in your CustomSignInManager class.
Here is a reference to the C# Language Specification
One thing to notice is that the return type has to be same.
So in your case you might want to create a new method rather than overriding the method.
There is no return type covariance in C#

It's not possible to change the return type when overriding a method.
C#: Overriding return types
Microsoft has an open issue for it on GitHub though: https://github.com/dotnet/csharplang/issues/49
It's not marked for implementation/release anytime soon though.

Related

Get userId from JWT on all Controller methods?

I am creating a Core 2.0 Web API project that uses JWT for authentication and authorization. My controller methods that I want to secure are all decorated with the Authorize attribute.
This is working. If I pass the JWT in the Bearer header, I get a 200. If I fail to pass the JWT, I get the 401. All working. In my JWT, I have stored the User ID in the 'UserId' field when authorizing..
var claimsdata = new[] {
new Claim("UserId", user.Id.ToString()),
I then have an extension method:
public static string GetUserId(this IPrincipal user)
{
if (user == null)
return string.Empty;
var identity = (ClaimsIdentity)user.Identity;
IEnumerable<Claim> claims = identity.Claims;
return claims.FirstOrDefault(s => s.Type == "UserId")?.Value;
}
On my controller method, with 'Authorize', I often need the ID of the user. So I call my GetUserId method. This works. However, I am unsure if this is the best way to get the Id from the token.
int.TryParse(User.GetUserId(), out _userId);
I need to use that code on all controllers. I can't do it in the constructor, as .. that's wrong I think.
Am I doing the right thing here?
ControllerBase contains User property that is type of ClaimsPrincipal
You can access user claims by User.Claims and no need for IPrincipal
Create a base controller which contains GetUserId method as protected
public abstract class BaseController : Controller
{
protected int GetUserId()
{
return int.Parse(this.User.Claims.First(i => i.Type == "UserId").Value);
}
}
And all controllers inherit form this, now all controllers can access UserId
Firstly I create IUserProvider interface with IHttpContextAccessor injection to make mocks for these interfaces in unit tests.
public interface IUserProvider
{
string GetUserId();
}
Than implementation is
public class UserProvider : IUserProvider
{
private readonly IHttpContextAccessor _context;
public UserProvider (IHttpContextAccessor context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
}
public string GetUserId()
{
return _context.HttpContext.User.Claims
.First(i => i.Type == ClaimTypes.NameIdentifier).Value;
}
}
So you can use interface IUserProvider in your controller without inheritance
[Authorize]
[ApiController]
public class MyController : ControllerBase
{
private readonly IUserProvider _userProvider;
public MyController(IUserProvider userProvider)
{
_userProvider = userProvider ?? throw new ArgumentNullException(nameof(userProvider ));
}
[HttpGet]
[Route("api/My/Something")]
public async Task<ActionResult> GetSomething()
{
try
{
var userId= _userProvider.GetUserId();
}
}
}
Also you can use
Extension Method
like this
public static long GetUserID(this ClaimsPrincipal User)
{
return long.Parse(User.Claims.First(i => i.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier").Value);
}
and implement in your controller like this
[HttpDelete("DeleteAddress")]
public async Task<IActionResult> DeleteAddress([FromQuery] long AddressID)
{
try
{
long userID = this.User.GetUserID();
await _addressService.Delete(userID, AddressID);
return Ok();
}
catch (Exception err)
{
return Conflict(err.Message);
}
}
I hope it will help you
var authenticatedUser = User.Identities.Select(c => c.Claims).ToArray()[0].ToArray()[0];
var userid = await userManager.FindByNameAsync(authenticatedUser['email']).Id;

ASP.NET Boilerplate: Get and GetAll is POST instead of GET method

I'm using the ASP.NET Boilerplate framework to do a small project and I used Swagger UI Integration to check the API within the project. I noticed that the Get and GetAll are still using POST method while the others are in their respective HTTP verb for example Create is POST, Edit is UPDATE, etc... I read the documentation and tried what they suggested in this [Documentation]
(https://aspnetboilerplate.com/Pages/Documents/Dynamic-Web-API#http-verbs)
Edit 1: Code for UserAppServiceClass
[AbpAuthorize(PermissionNames.Pages_Users)]
public class UserAppService : AsyncCrudAppService<User, UserDto, long, PagedResultRequestDto, CreateUserDto, UpdateUserDto>, IUserAppService
{
private readonly UserManager _userManager;
private readonly RoleManager _roleManager;
private readonly IRepository<Role> _roleRepository;
public UserAppService(
IRepository<User, long> repository,
UserManager userManager,
IRepository<Role> roleRepository,
RoleManager roleManager)
: base(repository)
{
_userManager = userManager;
_roleRepository = roleRepository;
_roleManager = roleManager;
}
[HttpGet]
public override async Task<UserDto> Get(EntityDto<long> input)
{
var user = await base.Get(input);
var userRoles = await _userManager.GetRolesAsync(user.Id);
user.Roles = userRoles.Select(ur => ur).ToArray();
return user;
}
[HttpPost]
public override async Task<UserDto> Create(CreateUserDto input)
{
CheckCreatePermission();
var user = ObjectMapper.Map<User>(input);
user.TenantId = AbpSession.TenantId;
user.Password = new PasswordHasher().HashPassword(input.Password);
user.IsEmailConfirmed = true;
//Assign roles
user.Roles = new Collection<UserRole>();
foreach (var roleName in input.RoleNames)
{
var role = await _roleManager.GetRoleByNameAsync(roleName);
user.Roles.Add(new UserRole(AbpSession.TenantId, user.Id, role.Id));
}
CheckErrors(await _userManager.CreateAsync(user));
return MapToEntityDto(user);
}
[HttpPut]
public override async Task<UserDto> Update(UpdateUserDto input)
{
CheckUpdatePermission();
var user = await _userManager.GetUserByIdAsync(input.Id);
MapToEntity(input, user);
CheckErrors(await _userManager.UpdateAsync(user));
if (input.RoleNames != null)
{
CheckErrors(await _userManager.SetRoles(user, input.RoleNames));
}
return await Get(input);
}
[HttpDelete]
public override async Task Delete(EntityDto<long> input)
{
var user = await _userManager.GetUserByIdAsync(input.Id);
await _userManager.DeleteAsync(user);
}
[HttpGet]
public async Task<ListResultDto<RoleDto>> GetRoles()
{
var roles = await _roleRepository.GetAllListAsync();
return new ListResultDto<RoleDto>(ObjectMapper.Map<List<RoleDto>>(roles));
}
protected override User MapToEntity(CreateUserDto createInput)
{
var user = ObjectMapper.Map<User>(createInput);
return user;
}
protected override void MapToEntity(UpdateUserDto input, User user)
{
ObjectMapper.Map(input, user);
}
protected override IQueryable<User> CreateFilteredQuery(PagedResultRequestDto input)
{
return Repository.GetAllIncluding(x => x.Roles);
}
protected override async Task<User> GetEntityByIdAsync(long id)
{
var user = Repository.GetAllIncluding(x => x.Roles).FirstOrDefault(x => x.Id == id);
return await Task.FromResult(user);
}
protected override IQueryable<User> ApplySorting(IQueryable<User> query, PagedResultRequestDto input)
{
return query.OrderBy(r => r.UserName);
}
protected virtual void CheckErrors(IdentityResult identityResult)
{
identityResult.CheckErrors(LocalizationManager);
}
}
Edit 2:
Your Get method has complex input argument: Get(EntityDto<long> input). HTTP GET verb can't pass it to server, that is why ASP.NET Boilerplate has no choice, it decide to assign POST verb instead. Only parameters like /Get?name=Max&age=22 are allowed for GET - at this case method's signature will be like this: Get(string name, int age).
So you should leave all of it without changes or change signature to flattern variant, enumerating properties of EntityDto<long> as comma separated arguments.
You have to write Http Verb attributes to the interface. Not to the method implementations!
public interface IUserAppService: IApplicationService
{
[HttpGet]
GetUserOutput Get(GetInput input);
[HttpGet]
GetAllOutput GetAll(GetAllInput input);
}
Do it for IAsyncCrudAppService
PS: For the methods come from base, you can new them in your interface.

How to use custom Authorize attribute in Asp.Net Core? [duplicate]

I'm trying to make a custom authorization attribute in ASP.NET Core. In previous versions it was possible to override bool AuthorizeCore(HttpContextBase httpContext). But this no longer exists in AuthorizeAttribute.
What is the current approach to make a custom AuthorizeAttribute?
What I am trying to accomplish: I am receiving a session ID in the Header Authorization. From that ID I'll know whether a particular action is valid.
The approach recommended by the ASP.Net Core team is to use the new policy design which is fully documented here. The basic idea behind the new approach is to use the new [Authorize] attribute to designate a "policy" (e.g. [Authorize( Policy = "YouNeedToBe18ToDoThis")] where the policy is registered in the application's Startup.cs to execute some block of code (i.e. ensure the user has an age claim where the age is 18 or older).
The policy design is a great addition to the framework and the ASP.Net Security Core team should be commended for its introduction. That said, it isn't well-suited for all cases. The shortcoming of this approach is that it fails to provide a convenient solution for the most common need of simply asserting that a given controller or action requires a given claim type. In the case where an application may have hundreds of discrete permissions governing CRUD operations on individual REST resources ("CanCreateOrder", "CanReadOrder", "CanUpdateOrder", "CanDeleteOrder", etc.), the new approach either requires repetitive one-to-one mappings between a policy name and a claim name (e.g. options.AddPolicy("CanUpdateOrder", policy => policy.RequireClaim(MyClaimTypes.Permission, "CanUpdateOrder));), or writing some code to perform these registrations at run time (e.g. read all claim types from a database and perform the aforementioned call in a loop). The problem with this approach for the majority of cases is that it's unnecessary overhead.
While the ASP.Net Core Security team recommends never creating your own solution, in some cases this may be the most prudent option with which to start.
The following is an implementation which uses the IAuthorizationFilter to provide a simple way to express a claim requirement for a given controller or action:
public class ClaimRequirementAttribute : TypeFilterAttribute
{
public ClaimRequirementAttribute(string claimType, string claimValue) : base(typeof(ClaimRequirementFilter))
{
Arguments = new object[] {new Claim(claimType, claimValue) };
}
}
public class ClaimRequirementFilter : IAuthorizationFilter
{
readonly Claim _claim;
public ClaimRequirementFilter(Claim claim)
{
_claim = claim;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var hasClaim = context.HttpContext.User.Claims.Any(c => c.Type == _claim.Type && c.Value == _claim.Value);
if (!hasClaim)
{
context.Result = new ForbidResult();
}
}
}
[Route("api/resource")]
public class MyController : Controller
{
[ClaimRequirement(MyClaimTypes.Permission, "CanReadResource")]
[HttpGet]
public IActionResult GetResource()
{
return Ok();
}
}
I'm the asp.net security person. Firstly let me apologize that none of this is documented yet outside of the music store sample or unit tests, and it's all still being refined in terms of exposed APIs. Detailed documentation is here.
We don't want you writing custom authorize attributes. If you need to do that we've done something wrong. Instead, you should be writing authorization requirements.
Authorization acts upon Identities. Identities are created by authentication.
You say in comments you want to check a session ID in a header. Your session ID would be the basis for identity. If you wanted to use the Authorize attribute you'd write an authentication middleware to take that header and turn it into an authenticated ClaimsPrincipal. You would then check that inside an authorization requirement. Authorization requirements can be as complicated as you like, for example here's one that takes a date of birth claim on the current identity and will authorize if the user is over 18;
public class Over18Requirement : AuthorizationHandler<Over18Requirement>, IAuthorizationRequirement
{
public override void Handle(AuthorizationHandlerContext context, Over18Requirement requirement)
{
if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth))
{
context.Fail();
return;
}
var dobVal = context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value;
var dateOfBirth = Convert.ToDateTime(dobVal);
int age = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-age))
{
age--;
}
if (age >= 18)
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
}
Then in your ConfigureServices() function you'd wire it up
services.AddAuthorization(options =>
{
options.AddPolicy("Over18",
policy => policy.Requirements.Add(new Authorization.Over18Requirement()));
});
And finally, apply it to a controller or action method with
[Authorize(Policy = "Over18")]
It seems that with ASP.NET Core 2, you can again inherit AuthorizeAttribute, you just need to also implement IAuthorizationFilter (or IAsyncAuthorizationFilter):
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
{
private readonly string _someFilterParameter;
public CustomAuthorizeAttribute(string someFilterParameter)
{
_someFilterParameter = someFilterParameter;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var user = context.HttpContext.User;
if (!user.Identity.IsAuthenticated)
{
// it isn't needed to set unauthorized result
// as the base class already requires the user to be authenticated
// this also makes redirect to a login page work properly
// context.Result = new UnauthorizedResult();
return;
}
// you can also use registered services
var someService = context.HttpContext.RequestServices.GetService<ISomeService>();
var isAuthorized = someService.IsUserAuthorized(user.Identity.Name, _someFilterParameter);
if (!isAuthorized)
{
context.Result = new StatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
return;
}
}
}
Based on Derek Greer GREAT answer, i did it with enums.
Here is an example of my code:
public enum PermissionItem
{
User,
Product,
Contact,
Review,
Client
}
public enum PermissionAction
{
Read,
Create,
}
public class AuthorizeAttribute : TypeFilterAttribute
{
public AuthorizeAttribute(PermissionItem item, PermissionAction action)
: base(typeof(AuthorizeActionFilter))
{
Arguments = new object[] { item, action };
}
}
public class AuthorizeActionFilter : IAuthorizationFilter
{
private readonly PermissionItem _item;
private readonly PermissionAction _action;
public AuthorizeActionFilter(PermissionItem item, PermissionAction action)
{
_item = item;
_action = action;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
bool isAuthorized = MumboJumboFunction(context.HttpContext.User, _item, _action); // :)
if (!isAuthorized)
{
context.Result = new ForbidResult();
}
}
}
public class UserController : BaseController
{
private readonly DbContext _context;
public UserController( DbContext context) :
base()
{
_logger = logger;
}
[Authorize(PermissionItem.User, PermissionAction.Read)]
public async Task<IActionResult> Index()
{
return View(await _context.User.ToListAsync());
}
}
You can create your own AuthorizationHandler that will find custom attributes on your Controllers and Actions, and pass them to the HandleRequirementAsync method.
public abstract class AttributeAuthorizationHandler<TRequirement, TAttribute> : AuthorizationHandler<TRequirement> where TRequirement : IAuthorizationRequirement where TAttribute : Attribute
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)
{
var attributes = new List<TAttribute>();
var action = (context.Resource as AuthorizationFilterContext)?.ActionDescriptor as ControllerActionDescriptor;
if (action != null)
{
attributes.AddRange(GetAttributes(action.ControllerTypeInfo.UnderlyingSystemType));
attributes.AddRange(GetAttributes(action.MethodInfo));
}
return HandleRequirementAsync(context, requirement, attributes);
}
protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement, IEnumerable<TAttribute> attributes);
private static IEnumerable<TAttribute> GetAttributes(MemberInfo memberInfo)
{
return memberInfo.GetCustomAttributes(typeof(TAttribute), false).Cast<TAttribute>();
}
}
Then you can use it for any custom attributes you need on your controllers or actions. For example to add permission requirements. Just create your custom attribute.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class PermissionAttribute : AuthorizeAttribute
{
public string Name { get; }
public PermissionAttribute(string name) : base("Permission")
{
Name = name;
}
}
Then create a Requirement to add to your Policy
public class PermissionAuthorizationRequirement : IAuthorizationRequirement
{
//Add any custom requirement properties if you have them
}
Then create the AuthorizationHandler for your custom attribute, inheriting the AttributeAuthorizationHandler that we created earlier. It will be passed an IEnumerable for all your custom attributes in the HandleRequirementsAsync method, accumulated from your Controller and Action.
public class PermissionAuthorizationHandler : AttributeAuthorizationHandler<PermissionAuthorizationRequirement, PermissionAttribute>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement, IEnumerable<PermissionAttribute> attributes)
{
foreach (var permissionAttribute in attributes)
{
if (!await AuthorizeAsync(context.User, permissionAttribute.Name))
{
return;
}
}
context.Succeed(requirement);
}
private Task<bool> AuthorizeAsync(ClaimsPrincipal user, string permission)
{
//Implement your custom user permission logic here
}
}
And finally, in your Startup.cs ConfigureServices method, add your custom AuthorizationHandler to the services, and add your Policy.
services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy("Permission", policyBuilder =>
{
policyBuilder.Requirements.Add(new PermissionAuthorizationRequirement());
});
});
Now you can simply decorate your Controllers and Actions with your custom attribute.
[Permission("AccessCustomers")]
public class CustomersController
{
[Permission("AddCustomer")]
IActionResult AddCustomer([FromBody] Customer customer)
{
//Add customer
}
}
What is the current approach to make a custom AuthorizeAttribute
For pure authorization scenarios (like restricting access to specific users only), the recommended approach is to use the new authorization block: https://github.com/aspnet/MusicStore/blob/1c0aeb08bb1ebd846726232226279bbe001782e1/samples/MusicStore/Startup.cs#L84-L92
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.Configure<AuthorizationOptions>(options =>
{
options.AddPolicy("ManageStore", policy => policy.RequireClaim("Action", "ManageStore"));
});
}
}
public class StoreController : Controller
{
[Authorize(Policy = "ManageStore"), HttpGet]
public async Task<IActionResult> Manage() { ... }
}
For authentication, it's best handled at the middleware level.
What are you trying to achieve exactly?
What?!
I decided to add another simple answer. B/c I find most of these answers a little overengineered. And also because I needed a way to GRANT authorization, not just DENY it. Most of the answers here offer a way to "tighten" security, but I wanted to "loosen" it. For example: "if some application setting is configured, then allow access to anonymous users".
public class MyAuthAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
//check access
if (CheckPermissions())
{
//all good, add optional code if you want. Or don't
}
else
{
//DENIED!
//return "ChallengeResult" to redirect to login page (for example)
context.Result = new ChallengeResult(CookieAuthenticationDefaults.AuthenticationScheme);
}
}
}
That's it. No need to mess with "policies", "claims", "handlers" and other [beep]
Usage:
// GET api/Get/5
[MyAuth]
public ActionResult<string> Get(int id)
{
return "blahblah";
}
The modern way is AuthenticationHandlers
in startup.cs add
services.AddAuthentication("BasicAuthentication").AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly IUserService _userService;
public BasicAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
IUserService userService)
: base(options, logger, encoder, clock)
{
_userService = userService;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey("Authorization"))
return AuthenticateResult.Fail("Missing Authorization Header");
User user = null;
try
{
var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
var username = credentials[0];
var password = credentials[1];
user = await _userService.Authenticate(username, password);
}
catch
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
if (user == null)
return AuthenticateResult.Fail("Invalid User-name or Password");
var claims = new[] {
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
};
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
}
IUserService is a service that you make where you have user name and password.
basically it returns a user class that you use to map your claims on.
var claims = new[] {
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
};
Then you can query these claims and her any data you mapped, ther are quite a few, have a look at ClaimTypes class
you can use this in an extension method an get any of the mappings
public int? GetUserId()
{
if (context.User.Identity.IsAuthenticated)
{
var id=context.User.FindFirst(ClaimTypes.NameIdentifier);
if (!(id is null) && int.TryParse(id.Value, out var userId))
return userId;
}
return new Nullable<int>();
}
This new way, i think is better than the old way as shown here, both work
public class BasicAuthenticationAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization != null)
{
var authToken = actionContext.Request.Headers.Authorization.Parameter;
// decoding authToken we get decode value in 'Username:Password' format
var decodeauthToken = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(authToken));
// spliting decodeauthToken using ':'
var arrUserNameandPassword = decodeauthToken.Split(':');
// at 0th postion of array we get username and at 1st we get password
if (IsAuthorizedUser(arrUserNameandPassword[0], arrUserNameandPassword[1]))
{
// setting current principle
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(arrUserNameandPassword[0]), null);
}
else
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}
}
else
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}
}
public static bool IsAuthorizedUser(string Username, string Password)
{
// In this method we can handle our database logic here...
return Username.Equals("test") && Password == "test";
}
}
If anyone just wants to validate a bearer token in the authorize phase using the current security practices you can,
add this to your Startup/ConfigureServices
services.AddSingleton<IAuthorizationHandler, BearerAuthorizationHandler>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer();
services.AddAuthorization(options => options.AddPolicy("Bearer",
policy => policy.AddRequirements(new BearerRequirement())
)
);
and this in your codebase,
public class BearerRequirement : IAuthorizationRequirement
{
public async Task<bool> IsTokenValid(SomeValidationContext context, string token)
{
// here you can check if the token received is valid
return true;
}
}
public class BearerAuthorizationHandler : AuthorizationHandler<BearerRequirement>
{
public BearerAuthorizationHandler(SomeValidationContext thatYouCanInject)
{
...
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, BearerRequirement requirement)
{
var authFilterCtx = (Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext)context.Resource;
string authHeader = authFilterCtx.HttpContext.Request.Headers["Authorization"];
if (authHeader != null && authHeader.Contains("Bearer"))
{
var token = authHeader.Replace("Bearer ", string.Empty);
if (await requirement.IsTokenValid(thatYouCanInject, token))
{
context.Succeed(requirement);
}
}
}
}
If the code doesn't reach context.Succeed(...) it will Fail anyway (401).
And then in your controllers you can use
[Authorize(Policy = "Bearer", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
The below code worked for me in .Net Core 5
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AccessAuthorizationAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public string Module { get; set; } //Permission string to get from controller
public AccessAuthorizationAttribute(string module)
{
Module = module;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
//Validate if any permissions are passed when using attribute at controller or action level
if (string.IsNullOrEmpty(Module))
{
//Validation cannot take place without any permissions so returning unauthorized
context.Result = new UnauthorizedResult();
return;
}
if (hasAccess)
{
return;
}
context.Result = new UnauthorizedResult();
return;
}
}
The accepted answer (https://stackoverflow.com/a/41348219/4974715) is not realistically maintainable or suitable because "CanReadResource" is being used as a claim (but should essentially be a policy in reality, IMO). The approach at the answer is not OK in the way it was used, because if an action method requires many different claims setups, then with that answer you would have to repeatedly write something like...
[ClaimRequirement(MyClaimTypes.Permission, "CanReadResource")]
[ClaimRequirement(MyClaimTypes.AnotherPermision, "AnotherClaimVaue")]
//and etc. on a single action.
So, imagine how much coding that would take. Ideally, "CanReadResource" is supposed to be a policy that uses many claims to determine if a user can read a resource.
What I do is I create my policies as an enumeration and then loop through and set up the requirements like thus...
services.AddAuthorization(authorizationOptions =>
{
foreach (var policyString in Enum.GetNames(typeof(Enumerations.Security.Policy)))
{
authorizationOptions.AddPolicy(
policyString,
authorizationPolicyBuilder => authorizationPolicyBuilder.Requirements.Add(new DefaultAuthorizationRequirement((Enumerations.Security.Policy)Enum.Parse(typeof(Enumerations.Security.Policy), policyWrtString), DateTime.UtcNow)));
/* Note that thisn does not stop you from
configuring policies directly against a username, claims, roles, etc. You can do the usual.
*/
}
});
The DefaultAuthorizationRequirement class looks like...
public class DefaultAuthorizationRequirement : IAuthorizationRequirement
{
public Enumerations.Security.Policy Policy {get; set;} //This is a mere enumeration whose code is not shown.
public DateTime DateTimeOfSetup {get; set;} //Just in case you have to know when the app started up. And you may want to log out a user if their profile was modified after this date-time, etc.
}
public class DefaultAuthorizationHandler : AuthorizationHandler<DefaultAuthorizationRequirement>
{
private IAServiceToUse _aServiceToUse;
public DefaultAuthorizationHandler(
IAServiceToUse aServiceToUse
)
{
_aServiceToUse = aServiceToUse;
}
protected async override Task HandleRequirementAsync(AuthorizationHandlerContext context, DefaultAuthorizationRequirement requirement)
{
/*Here, you can quickly check a data source or Web API or etc.
to know the latest date-time of the user's profile modification...
*/
if (_aServiceToUse.GetDateTimeOfLatestUserProfileModication > requirement.DateTimeOfSetup)
{
context.Fail(); /*Because any modifications to user information,
e.g. if the user used another browser or if by Admin modification,
the claims of the user in this session cannot be guaranteed to be reliable.
*/
return;
}
bool shouldSucceed = false; //This should first be false, because context.Succeed(...) has to only be called if the requirement specifically succeeds.
bool shouldFail = false; /*This should first be false, because context.Fail()
doesn't have to be called if there's no security breach.
*/
// You can do anything.
await doAnythingAsync();
/*You can get the user's claims...
ALSO, note that if you have a way to priorly map users or users with certain claims
to particular policies, add those policies as claims of the user for the sake of ease.
BUT policies that require dynamic code (e.g. checking for age range) would have to be
coded in the switch-case below to determine stuff.
*/
var claims = context.User.Claims;
// You can, of course, get the policy that was hit...
var policy = requirement.Policy
//You can use a switch case to determine what policy to deal with here...
switch (policy)
{
case Enumerations.Security.Policy.CanReadResource:
/*Do stuff with the claims and change the
value of shouldSucceed and/or shouldFail.
*/
break;
case Enumerations.Security.Policy.AnotherPolicy:
/*Do stuff with the claims and change the
value of shouldSucceed and/or shouldFail.
*/
break;
// Other policies too.
default:
throw new NotImplementedException();
}
/* Note that the following conditions are
so because failure and success in a requirement handler
are not mutually exclusive. They demand certainty.
*/
if (shouldFail)
{
context.Fail(); /*Check the docs on this method to
see its implications.
*/
}
if (shouldSucceed)
{
context.Succeed(requirement);
}
}
}
Note that the code above can also enable pre-mapping of a user to a policy in your data store. So, when composing claims for the user, you basically retrieve the policies that had been pre-mapped to the user directly or indirectly (e.g. because the user has a certain claim value and that claim value had been identified and mapped to a policy, such that it provides automatic mapping for users who have that claim value too), and enlist the policies as claims, such that in the authorization handler, you can simply check if the user's claims contain requirement.Policy as a Value of a Claim item in their claims. That is for a static way of satisfying a policy requirement, e.g. "First name" requirement is quite static in nature. So, for the example above (which I had forgotten to give example on Authorize attribute in my earlier updates to this answer), using the policy with Authorize attribute is like as follows, where ViewRecord is an enum member:
[Authorize(Policy = nameof(Enumerations.Security.Policy.ViewRecord))]
A dynamic requirement can be about checking age range, etc. and policies that use such requirements cannot be pre-mapped to users.
An example of dynamic policy claims checking (e.g. to check if a user is above 18 years old) is already at the answer given by #blowdart (https://stackoverflow.com/a/31465227/4974715).
PS: I typed this on my phone. Pardon any typos and lack of formatting.
As of this writing I believe this can be accomplished with the IClaimsTransformation interface in asp.net core 2 and above. I just implemented a proof of concept which is sharable enough to post here.
public class PrivilegesToClaimsTransformer : IClaimsTransformation
{
private readonly IPrivilegeProvider privilegeProvider;
public const string DidItClaim = "http://foo.bar/privileges/resolved";
public PrivilegesToClaimsTransformer(IPrivilegeProvider privilegeProvider)
{
this.privilegeProvider = privilegeProvider;
}
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
if (principal.Identity is ClaimsIdentity claimer)
{
if (claimer.HasClaim(DidItClaim, bool.TrueString))
{
return principal;
}
var privileges = await this.privilegeProvider.GetPrivileges( ... );
claimer.AddClaim(new Claim(DidItClaim, bool.TrueString));
foreach (var privilegeAsRole in privileges)
{
claimer.AddClaim(new Claim(ClaimTypes.Role /*"http://schemas.microsoft.com/ws/2008/06/identity/claims/role" */, privilegeAsRole));
}
}
return principal;
}
}
To use this in your Controller just add an appropriate [Authorize(Roles="whatever")] to your methods.
[HttpGet]
[Route("poc")]
[Authorize(Roles = "plugh,blast")]
public JsonResult PocAuthorization()
{
var result = Json(new
{
when = DateTime.UtcNow,
});
result.StatusCode = (int)HttpStatusCode.OK;
return result;
}
In our case every request includes an Authorization header that is a JWT. This is the prototype and I believe we will do something super close to this in our production system next week.
Future voters, consider the date of writing when you vote. As of today, this works on my machine.™ You will probably want more error handling and logging on your implementation.
Just adding to the great answer from #Shawn. If you are using dotnet 5 you need to update the class to be:
public abstract class AttributeAuthorizationHandler<TRequirement, TAttribute> : AuthorizationHandler<TRequirement> where TRequirement : IAuthorizationRequirement where TAttribute : Attribute
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)
{
var attributes = new List<TAttribute>();
if (context.Resource is HttpContext httpContext)
{
var endPoint = httpContext.GetEndpoint();
var action = endPoint?.Metadata.GetMetadata<ControllerActionDescriptor>();
if(action != null)
{
attributes.AddRange(GetAttributes(action.ControllerTypeInfo.UnderlyingSystemType));
attributes.AddRange(GetAttributes(action.MethodInfo));
}
}
return HandleRequirementAsync(context, requirement, attributes);
}
protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement, IEnumerable<TAttribute> attributes);
private static IEnumerable<TAttribute> GetAttributes(MemberInfo memberInfo) => memberInfo.GetCustomAttributes(typeof(TAttribute), false).Cast<TAttribute>();
}
Noting the way getting the ControllerActionDescriptor has changed.
I have bearer token and I can read claims.
I use that attribute on controllers and actions
public class CustomAuthorizationAttribute : ActionFilterAttribute
{
public string[] Claims;
public override void OnActionExecuting(ActionExecutingContext context)
{
// check user
var contextUser = context?.HttpContext?.User;
if (contextUser == null)
{
throw new BusinessException("Forbidden");
}
// check roles
var roles = contextUser.FindAll("http://schemas.microsoft.com/ws/2008/06/identity/claims/role").Select(c => c.Value).ToList();
if (!roles.Any(s => Claims.Contains(s)))
{
throw new BusinessException("Forbidden");
}
base.OnActionExecuting(context);
}
}
example
[CustomAuthorization(Claims = new string[]
{
nameof(AuthorizationRole.HR_ADMIN),
nameof(AuthorizationRole.HR_SETTING)
})]
[Route("api/[controller]")]
[ApiController]
public class SomeAdminController : ControllerBase
{
private readonly IMediator _mediator;
public SomeAdminController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet("list/SomeList")]
public async Task<IActionResult> SomeList()
=> Ok(await _mediator.Send(new SomeListQuery()));
}
That is Roles
public struct AuthorizationRole
{
public static string HR_ADMIN;
public static string HR_SETTING;
}
Here's a simple 5-step guide for how to implement custom role authorization using policies for all you copy and pasters out there :) . I used these docs.
Create a requirement:
public class RoleRequirement : IAuthorizationRequirement
{
public string Role { get; set; }
}
Create a handler:
public class RoleHandler : AuthorizationHandler<RoleRequirement>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
{
var requiredRole = requirement.Role;
//custom auth logic
// you can use context to access authenticated user,
// you can use dependecy injection to call custom services
var hasRole = true;
if (hasRole)
{
context.Succeed(requirement);
}
else
{
context.Fail(new AuthorizationFailureReason(this, $"Role {requirement.Role} missing"));
}
}
}
Add the handler in Program.cs:
builder.Services.AddSingleton<IAuthorizationHandler, RoleHandler>();
Add a policy with your role requirement in program.cs:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("Read", policy => policy.Requirements.Add(new RoleRequirement{Role = "ReadAccess_Custom_System"}));
});
Use your policy:
[Authorize("Read")]
public class ExampleController : ControllerBase
{
}
A lot of people here already told this, but with Policy handlers you can come really far in terms of what you could achieve with the old way in .NET Framework.
I followed a quick writeup from this answer on SO: https://stackoverflow.com/a/61963465/7081176
For me it works flawlessly after making some classes:
The EditUserRequirement:
public class EditUserRequirement : IAuthorizationRequirement
{
public EditUserRequirement()
{
}
}
An abstract handler to make my life easier:
public abstract class AbstractRequirementHandler<T> : IAuthorizationHandler
where T : IAuthorizationRequirement
{
public async Task HandleAsync(AuthorizationHandlerContext context)
{
var pendingRequirements = context.PendingRequirements.ToList();
foreach (var requirement in pendingRequirements)
{
if (requirement is T typedRequirement)
{
await HandleRequirementAsync(context, typedRequirement);
}
}
}
protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, T requirement);
}
An implementation of the abstract handler:
public class EditUserRequirementHandler : AbstractRequirementHandler<EditUserRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, EditUserRequirement requirement)
{
// If the user is owner of the resource, allow it.
if (IsOwner(context.User, g))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
private static bool IsOwner(ClaimsPrincipal user, Guid userIdentifier)
{
return user.GetUserIdentifier() == userIdentifier;
}
}
Registering my handler and requirement:
services.AddSingleton<IAuthorizationHandler, EditUserRequirementHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy(Policies.Policies.EditUser, policy =>
{
policy.Requirements.Add(new EditUserRequirement());
});
});
And then using my Policy in Blazor:
<AuthorizeView Policy="#Policies.EditUser" Resource="#id">
<NotAuthorized>
<Unauthorized />
</NotAuthorized>
<Authorized Context="Auth">
...
</Authorized>
</AuthorizeView>
I hope this is useful for anyone facing this issue.
I have been looking into solving a very similar issue, and settled on creating a custom ActionFilterAttribute (I'm going to call it AuthorizationFilterAttribute) instead of an AuthorizeAttribute to implement the guidance here: https://learn.microsoft.com/en-us/aspnet/core/security/authorization/resourcebased?view=aspnetcore-6.0#challenge-and-forbid-with-an-operational-resource-handler.
For authorization in our app. We had to call a service based on the parameters passed in authorization attribute.
For example, if we want to check if logged in doctor can view patient appointments we will pass "View_Appointment" to custom authorize attribute and check that right in DB service and based on results we will athorize. Here is the code for this scenario:
public class PatientAuthorizeAttribute : TypeFilterAttribute
{
public PatientAuthorizeAttribute(params PatientAccessRights[] right) : base(typeof(AuthFilter)) //PatientAccessRights is an enum
{
Arguments = new object[] { right };
}
private class AuthFilter : IActionFilter
{
PatientAccessRights[] right;
IAuthService authService;
public AuthFilter(IAuthService authService, PatientAccessRights[] right)
{
this.right = right;
this.authService = authService;
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
var allparameters = context.ActionArguments.Values;
if (allparameters.Count() == 1)
{
var param = allparameters.First();
if (typeof(IPatientRequest).IsAssignableFrom(param.GetType()))
{
IPatientRequest patientRequestInfo = (IPatientRequest)param;
PatientAccessRequest userAccessRequest = new PatientAccessRequest();
userAccessRequest.Rights = right;
userAccessRequest.MemberID = patientRequestInfo.PatientID;
var result = authService.CheckUserPatientAccess(userAccessRequest).Result; //this calls DB service to check from DB
if (result.Status == ReturnType.Failure)
{
//TODO: return apirepsonse
context.Result = new StatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
}
}
else
{
throw new AppSystemException("PatientAuthorizeAttribute not supported");
}
}
else
{
throw new AppSystemException("PatientAuthorizeAttribute not supported");
}
}
}
}
And on API action we use it like this:
[PatientAuthorize(PatientAccessRights.PATIENT_VIEW_APPOINTMENTS)] //this is enum, we can pass multiple
[HttpPost]
public SomeReturnType ViewAppointments()
{
}

How to make a custom Authorize attribute in ASP.NET Core? [duplicate]

I'm trying to make a custom authorization attribute in ASP.NET Core. In previous versions it was possible to override bool AuthorizeCore(HttpContextBase httpContext). But this no longer exists in AuthorizeAttribute.
What is the current approach to make a custom AuthorizeAttribute?
What I am trying to accomplish: I am receiving a session ID in the Header Authorization. From that ID I'll know whether a particular action is valid.
The approach recommended by the ASP.Net Core team is to use the new policy design which is fully documented here. The basic idea behind the new approach is to use the new [Authorize] attribute to designate a "policy" (e.g. [Authorize( Policy = "YouNeedToBe18ToDoThis")] where the policy is registered in the application's Startup.cs to execute some block of code (i.e. ensure the user has an age claim where the age is 18 or older).
The policy design is a great addition to the framework and the ASP.Net Security Core team should be commended for its introduction. That said, it isn't well-suited for all cases. The shortcoming of this approach is that it fails to provide a convenient solution for the most common need of simply asserting that a given controller or action requires a given claim type. In the case where an application may have hundreds of discrete permissions governing CRUD operations on individual REST resources ("CanCreateOrder", "CanReadOrder", "CanUpdateOrder", "CanDeleteOrder", etc.), the new approach either requires repetitive one-to-one mappings between a policy name and a claim name (e.g. options.AddPolicy("CanUpdateOrder", policy => policy.RequireClaim(MyClaimTypes.Permission, "CanUpdateOrder));), or writing some code to perform these registrations at run time (e.g. read all claim types from a database and perform the aforementioned call in a loop). The problem with this approach for the majority of cases is that it's unnecessary overhead.
While the ASP.Net Core Security team recommends never creating your own solution, in some cases this may be the most prudent option with which to start.
The following is an implementation which uses the IAuthorizationFilter to provide a simple way to express a claim requirement for a given controller or action:
public class ClaimRequirementAttribute : TypeFilterAttribute
{
public ClaimRequirementAttribute(string claimType, string claimValue) : base(typeof(ClaimRequirementFilter))
{
Arguments = new object[] {new Claim(claimType, claimValue) };
}
}
public class ClaimRequirementFilter : IAuthorizationFilter
{
readonly Claim _claim;
public ClaimRequirementFilter(Claim claim)
{
_claim = claim;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var hasClaim = context.HttpContext.User.Claims.Any(c => c.Type == _claim.Type && c.Value == _claim.Value);
if (!hasClaim)
{
context.Result = new ForbidResult();
}
}
}
[Route("api/resource")]
public class MyController : Controller
{
[ClaimRequirement(MyClaimTypes.Permission, "CanReadResource")]
[HttpGet]
public IActionResult GetResource()
{
return Ok();
}
}
I'm the asp.net security person. Firstly let me apologize that none of this is documented yet outside of the music store sample or unit tests, and it's all still being refined in terms of exposed APIs. Detailed documentation is here.
We don't want you writing custom authorize attributes. If you need to do that we've done something wrong. Instead, you should be writing authorization requirements.
Authorization acts upon Identities. Identities are created by authentication.
You say in comments you want to check a session ID in a header. Your session ID would be the basis for identity. If you wanted to use the Authorize attribute you'd write an authentication middleware to take that header and turn it into an authenticated ClaimsPrincipal. You would then check that inside an authorization requirement. Authorization requirements can be as complicated as you like, for example here's one that takes a date of birth claim on the current identity and will authorize if the user is over 18;
public class Over18Requirement : AuthorizationHandler<Over18Requirement>, IAuthorizationRequirement
{
public override void Handle(AuthorizationHandlerContext context, Over18Requirement requirement)
{
if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth))
{
context.Fail();
return;
}
var dobVal = context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value;
var dateOfBirth = Convert.ToDateTime(dobVal);
int age = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-age))
{
age--;
}
if (age >= 18)
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
}
Then in your ConfigureServices() function you'd wire it up
services.AddAuthorization(options =>
{
options.AddPolicy("Over18",
policy => policy.Requirements.Add(new Authorization.Over18Requirement()));
});
And finally, apply it to a controller or action method with
[Authorize(Policy = "Over18")]
It seems that with ASP.NET Core 2, you can again inherit AuthorizeAttribute, you just need to also implement IAuthorizationFilter (or IAsyncAuthorizationFilter):
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
{
private readonly string _someFilterParameter;
public CustomAuthorizeAttribute(string someFilterParameter)
{
_someFilterParameter = someFilterParameter;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var user = context.HttpContext.User;
if (!user.Identity.IsAuthenticated)
{
// it isn't needed to set unauthorized result
// as the base class already requires the user to be authenticated
// this also makes redirect to a login page work properly
// context.Result = new UnauthorizedResult();
return;
}
// you can also use registered services
var someService = context.HttpContext.RequestServices.GetService<ISomeService>();
var isAuthorized = someService.IsUserAuthorized(user.Identity.Name, _someFilterParameter);
if (!isAuthorized)
{
context.Result = new StatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
return;
}
}
}
Based on Derek Greer GREAT answer, i did it with enums.
Here is an example of my code:
public enum PermissionItem
{
User,
Product,
Contact,
Review,
Client
}
public enum PermissionAction
{
Read,
Create,
}
public class AuthorizeAttribute : TypeFilterAttribute
{
public AuthorizeAttribute(PermissionItem item, PermissionAction action)
: base(typeof(AuthorizeActionFilter))
{
Arguments = new object[] { item, action };
}
}
public class AuthorizeActionFilter : IAuthorizationFilter
{
private readonly PermissionItem _item;
private readonly PermissionAction _action;
public AuthorizeActionFilter(PermissionItem item, PermissionAction action)
{
_item = item;
_action = action;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
bool isAuthorized = MumboJumboFunction(context.HttpContext.User, _item, _action); // :)
if (!isAuthorized)
{
context.Result = new ForbidResult();
}
}
}
public class UserController : BaseController
{
private readonly DbContext _context;
public UserController( DbContext context) :
base()
{
_logger = logger;
}
[Authorize(PermissionItem.User, PermissionAction.Read)]
public async Task<IActionResult> Index()
{
return View(await _context.User.ToListAsync());
}
}
You can create your own AuthorizationHandler that will find custom attributes on your Controllers and Actions, and pass them to the HandleRequirementAsync method.
public abstract class AttributeAuthorizationHandler<TRequirement, TAttribute> : AuthorizationHandler<TRequirement> where TRequirement : IAuthorizationRequirement where TAttribute : Attribute
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)
{
var attributes = new List<TAttribute>();
var action = (context.Resource as AuthorizationFilterContext)?.ActionDescriptor as ControllerActionDescriptor;
if (action != null)
{
attributes.AddRange(GetAttributes(action.ControllerTypeInfo.UnderlyingSystemType));
attributes.AddRange(GetAttributes(action.MethodInfo));
}
return HandleRequirementAsync(context, requirement, attributes);
}
protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement, IEnumerable<TAttribute> attributes);
private static IEnumerable<TAttribute> GetAttributes(MemberInfo memberInfo)
{
return memberInfo.GetCustomAttributes(typeof(TAttribute), false).Cast<TAttribute>();
}
}
Then you can use it for any custom attributes you need on your controllers or actions. For example to add permission requirements. Just create your custom attribute.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class PermissionAttribute : AuthorizeAttribute
{
public string Name { get; }
public PermissionAttribute(string name) : base("Permission")
{
Name = name;
}
}
Then create a Requirement to add to your Policy
public class PermissionAuthorizationRequirement : IAuthorizationRequirement
{
//Add any custom requirement properties if you have them
}
Then create the AuthorizationHandler for your custom attribute, inheriting the AttributeAuthorizationHandler that we created earlier. It will be passed an IEnumerable for all your custom attributes in the HandleRequirementsAsync method, accumulated from your Controller and Action.
public class PermissionAuthorizationHandler : AttributeAuthorizationHandler<PermissionAuthorizationRequirement, PermissionAttribute>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement, IEnumerable<PermissionAttribute> attributes)
{
foreach (var permissionAttribute in attributes)
{
if (!await AuthorizeAsync(context.User, permissionAttribute.Name))
{
return;
}
}
context.Succeed(requirement);
}
private Task<bool> AuthorizeAsync(ClaimsPrincipal user, string permission)
{
//Implement your custom user permission logic here
}
}
And finally, in your Startup.cs ConfigureServices method, add your custom AuthorizationHandler to the services, and add your Policy.
services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy("Permission", policyBuilder =>
{
policyBuilder.Requirements.Add(new PermissionAuthorizationRequirement());
});
});
Now you can simply decorate your Controllers and Actions with your custom attribute.
[Permission("AccessCustomers")]
public class CustomersController
{
[Permission("AddCustomer")]
IActionResult AddCustomer([FromBody] Customer customer)
{
//Add customer
}
}
What is the current approach to make a custom AuthorizeAttribute
For pure authorization scenarios (like restricting access to specific users only), the recommended approach is to use the new authorization block: https://github.com/aspnet/MusicStore/blob/1c0aeb08bb1ebd846726232226279bbe001782e1/samples/MusicStore/Startup.cs#L84-L92
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.Configure<AuthorizationOptions>(options =>
{
options.AddPolicy("ManageStore", policy => policy.RequireClaim("Action", "ManageStore"));
});
}
}
public class StoreController : Controller
{
[Authorize(Policy = "ManageStore"), HttpGet]
public async Task<IActionResult> Manage() { ... }
}
For authentication, it's best handled at the middleware level.
What are you trying to achieve exactly?
What?!
I decided to add another simple answer. B/c I find most of these answers a little overengineered. And also because I needed a way to GRANT authorization, not just DENY it. Most of the answers here offer a way to "tighten" security, but I wanted to "loosen" it. For example: "if some application setting is configured, then allow access to anonymous users".
public class MyAuthAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
//check access
if (CheckPermissions())
{
//all good, add optional code if you want. Or don't
}
else
{
//DENIED!
//return "ChallengeResult" to redirect to login page (for example)
context.Result = new ChallengeResult(CookieAuthenticationDefaults.AuthenticationScheme);
}
}
}
That's it. No need to mess with "policies", "claims", "handlers" and other [beep]
Usage:
// GET api/Get/5
[MyAuth]
public ActionResult<string> Get(int id)
{
return "blahblah";
}
The modern way is AuthenticationHandlers
in startup.cs add
services.AddAuthentication("BasicAuthentication").AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly IUserService _userService;
public BasicAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
IUserService userService)
: base(options, logger, encoder, clock)
{
_userService = userService;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey("Authorization"))
return AuthenticateResult.Fail("Missing Authorization Header");
User user = null;
try
{
var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
var username = credentials[0];
var password = credentials[1];
user = await _userService.Authenticate(username, password);
}
catch
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
if (user == null)
return AuthenticateResult.Fail("Invalid User-name or Password");
var claims = new[] {
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
};
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
}
IUserService is a service that you make where you have user name and password.
basically it returns a user class that you use to map your claims on.
var claims = new[] {
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
};
Then you can query these claims and her any data you mapped, ther are quite a few, have a look at ClaimTypes class
you can use this in an extension method an get any of the mappings
public int? GetUserId()
{
if (context.User.Identity.IsAuthenticated)
{
var id=context.User.FindFirst(ClaimTypes.NameIdentifier);
if (!(id is null) && int.TryParse(id.Value, out var userId))
return userId;
}
return new Nullable<int>();
}
This new way, i think is better than the old way as shown here, both work
public class BasicAuthenticationAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization != null)
{
var authToken = actionContext.Request.Headers.Authorization.Parameter;
// decoding authToken we get decode value in 'Username:Password' format
var decodeauthToken = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(authToken));
// spliting decodeauthToken using ':'
var arrUserNameandPassword = decodeauthToken.Split(':');
// at 0th postion of array we get username and at 1st we get password
if (IsAuthorizedUser(arrUserNameandPassword[0], arrUserNameandPassword[1]))
{
// setting current principle
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(arrUserNameandPassword[0]), null);
}
else
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}
}
else
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}
}
public static bool IsAuthorizedUser(string Username, string Password)
{
// In this method we can handle our database logic here...
return Username.Equals("test") && Password == "test";
}
}
If anyone just wants to validate a bearer token in the authorize phase using the current security practices you can,
add this to your Startup/ConfigureServices
services.AddSingleton<IAuthorizationHandler, BearerAuthorizationHandler>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer();
services.AddAuthorization(options => options.AddPolicy("Bearer",
policy => policy.AddRequirements(new BearerRequirement())
)
);
and this in your codebase,
public class BearerRequirement : IAuthorizationRequirement
{
public async Task<bool> IsTokenValid(SomeValidationContext context, string token)
{
// here you can check if the token received is valid
return true;
}
}
public class BearerAuthorizationHandler : AuthorizationHandler<BearerRequirement>
{
public BearerAuthorizationHandler(SomeValidationContext thatYouCanInject)
{
...
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, BearerRequirement requirement)
{
var authFilterCtx = (Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext)context.Resource;
string authHeader = authFilterCtx.HttpContext.Request.Headers["Authorization"];
if (authHeader != null && authHeader.Contains("Bearer"))
{
var token = authHeader.Replace("Bearer ", string.Empty);
if (await requirement.IsTokenValid(thatYouCanInject, token))
{
context.Succeed(requirement);
}
}
}
}
If the code doesn't reach context.Succeed(...) it will Fail anyway (401).
And then in your controllers you can use
[Authorize(Policy = "Bearer", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
The below code worked for me in .Net Core 5
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AccessAuthorizationAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public string Module { get; set; } //Permission string to get from controller
public AccessAuthorizationAttribute(string module)
{
Module = module;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
//Validate if any permissions are passed when using attribute at controller or action level
if (string.IsNullOrEmpty(Module))
{
//Validation cannot take place without any permissions so returning unauthorized
context.Result = new UnauthorizedResult();
return;
}
if (hasAccess)
{
return;
}
context.Result = new UnauthorizedResult();
return;
}
}
The accepted answer (https://stackoverflow.com/a/41348219/4974715) is not realistically maintainable or suitable because "CanReadResource" is being used as a claim (but should essentially be a policy in reality, IMO). The approach at the answer is not OK in the way it was used, because if an action method requires many different claims setups, then with that answer you would have to repeatedly write something like...
[ClaimRequirement(MyClaimTypes.Permission, "CanReadResource")]
[ClaimRequirement(MyClaimTypes.AnotherPermision, "AnotherClaimVaue")]
//and etc. on a single action.
So, imagine how much coding that would take. Ideally, "CanReadResource" is supposed to be a policy that uses many claims to determine if a user can read a resource.
What I do is I create my policies as an enumeration and then loop through and set up the requirements like thus...
services.AddAuthorization(authorizationOptions =>
{
foreach (var policyString in Enum.GetNames(typeof(Enumerations.Security.Policy)))
{
authorizationOptions.AddPolicy(
policyString,
authorizationPolicyBuilder => authorizationPolicyBuilder.Requirements.Add(new DefaultAuthorizationRequirement((Enumerations.Security.Policy)Enum.Parse(typeof(Enumerations.Security.Policy), policyWrtString), DateTime.UtcNow)));
/* Note that thisn does not stop you from
configuring policies directly against a username, claims, roles, etc. You can do the usual.
*/
}
});
The DefaultAuthorizationRequirement class looks like...
public class DefaultAuthorizationRequirement : IAuthorizationRequirement
{
public Enumerations.Security.Policy Policy {get; set;} //This is a mere enumeration whose code is not shown.
public DateTime DateTimeOfSetup {get; set;} //Just in case you have to know when the app started up. And you may want to log out a user if their profile was modified after this date-time, etc.
}
public class DefaultAuthorizationHandler : AuthorizationHandler<DefaultAuthorizationRequirement>
{
private IAServiceToUse _aServiceToUse;
public DefaultAuthorizationHandler(
IAServiceToUse aServiceToUse
)
{
_aServiceToUse = aServiceToUse;
}
protected async override Task HandleRequirementAsync(AuthorizationHandlerContext context, DefaultAuthorizationRequirement requirement)
{
/*Here, you can quickly check a data source or Web API or etc.
to know the latest date-time of the user's profile modification...
*/
if (_aServiceToUse.GetDateTimeOfLatestUserProfileModication > requirement.DateTimeOfSetup)
{
context.Fail(); /*Because any modifications to user information,
e.g. if the user used another browser or if by Admin modification,
the claims of the user in this session cannot be guaranteed to be reliable.
*/
return;
}
bool shouldSucceed = false; //This should first be false, because context.Succeed(...) has to only be called if the requirement specifically succeeds.
bool shouldFail = false; /*This should first be false, because context.Fail()
doesn't have to be called if there's no security breach.
*/
// You can do anything.
await doAnythingAsync();
/*You can get the user's claims...
ALSO, note that if you have a way to priorly map users or users with certain claims
to particular policies, add those policies as claims of the user for the sake of ease.
BUT policies that require dynamic code (e.g. checking for age range) would have to be
coded in the switch-case below to determine stuff.
*/
var claims = context.User.Claims;
// You can, of course, get the policy that was hit...
var policy = requirement.Policy
//You can use a switch case to determine what policy to deal with here...
switch (policy)
{
case Enumerations.Security.Policy.CanReadResource:
/*Do stuff with the claims and change the
value of shouldSucceed and/or shouldFail.
*/
break;
case Enumerations.Security.Policy.AnotherPolicy:
/*Do stuff with the claims and change the
value of shouldSucceed and/or shouldFail.
*/
break;
// Other policies too.
default:
throw new NotImplementedException();
}
/* Note that the following conditions are
so because failure and success in a requirement handler
are not mutually exclusive. They demand certainty.
*/
if (shouldFail)
{
context.Fail(); /*Check the docs on this method to
see its implications.
*/
}
if (shouldSucceed)
{
context.Succeed(requirement);
}
}
}
Note that the code above can also enable pre-mapping of a user to a policy in your data store. So, when composing claims for the user, you basically retrieve the policies that had been pre-mapped to the user directly or indirectly (e.g. because the user has a certain claim value and that claim value had been identified and mapped to a policy, such that it provides automatic mapping for users who have that claim value too), and enlist the policies as claims, such that in the authorization handler, you can simply check if the user's claims contain requirement.Policy as a Value of a Claim item in their claims. That is for a static way of satisfying a policy requirement, e.g. "First name" requirement is quite static in nature. So, for the example above (which I had forgotten to give example on Authorize attribute in my earlier updates to this answer), using the policy with Authorize attribute is like as follows, where ViewRecord is an enum member:
[Authorize(Policy = nameof(Enumerations.Security.Policy.ViewRecord))]
A dynamic requirement can be about checking age range, etc. and policies that use such requirements cannot be pre-mapped to users.
An example of dynamic policy claims checking (e.g. to check if a user is above 18 years old) is already at the answer given by #blowdart (https://stackoverflow.com/a/31465227/4974715).
PS: I typed this on my phone. Pardon any typos and lack of formatting.
As of this writing I believe this can be accomplished with the IClaimsTransformation interface in asp.net core 2 and above. I just implemented a proof of concept which is sharable enough to post here.
public class PrivilegesToClaimsTransformer : IClaimsTransformation
{
private readonly IPrivilegeProvider privilegeProvider;
public const string DidItClaim = "http://foo.bar/privileges/resolved";
public PrivilegesToClaimsTransformer(IPrivilegeProvider privilegeProvider)
{
this.privilegeProvider = privilegeProvider;
}
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
if (principal.Identity is ClaimsIdentity claimer)
{
if (claimer.HasClaim(DidItClaim, bool.TrueString))
{
return principal;
}
var privileges = await this.privilegeProvider.GetPrivileges( ... );
claimer.AddClaim(new Claim(DidItClaim, bool.TrueString));
foreach (var privilegeAsRole in privileges)
{
claimer.AddClaim(new Claim(ClaimTypes.Role /*"http://schemas.microsoft.com/ws/2008/06/identity/claims/role" */, privilegeAsRole));
}
}
return principal;
}
}
To use this in your Controller just add an appropriate [Authorize(Roles="whatever")] to your methods.
[HttpGet]
[Route("poc")]
[Authorize(Roles = "plugh,blast")]
public JsonResult PocAuthorization()
{
var result = Json(new
{
when = DateTime.UtcNow,
});
result.StatusCode = (int)HttpStatusCode.OK;
return result;
}
In our case every request includes an Authorization header that is a JWT. This is the prototype and I believe we will do something super close to this in our production system next week.
Future voters, consider the date of writing when you vote. As of today, this works on my machine.™ You will probably want more error handling and logging on your implementation.
Just adding to the great answer from #Shawn. If you are using dotnet 5 you need to update the class to be:
public abstract class AttributeAuthorizationHandler<TRequirement, TAttribute> : AuthorizationHandler<TRequirement> where TRequirement : IAuthorizationRequirement where TAttribute : Attribute
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)
{
var attributes = new List<TAttribute>();
if (context.Resource is HttpContext httpContext)
{
var endPoint = httpContext.GetEndpoint();
var action = endPoint?.Metadata.GetMetadata<ControllerActionDescriptor>();
if(action != null)
{
attributes.AddRange(GetAttributes(action.ControllerTypeInfo.UnderlyingSystemType));
attributes.AddRange(GetAttributes(action.MethodInfo));
}
}
return HandleRequirementAsync(context, requirement, attributes);
}
protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement, IEnumerable<TAttribute> attributes);
private static IEnumerable<TAttribute> GetAttributes(MemberInfo memberInfo) => memberInfo.GetCustomAttributes(typeof(TAttribute), false).Cast<TAttribute>();
}
Noting the way getting the ControllerActionDescriptor has changed.
I have bearer token and I can read claims.
I use that attribute on controllers and actions
public class CustomAuthorizationAttribute : ActionFilterAttribute
{
public string[] Claims;
public override void OnActionExecuting(ActionExecutingContext context)
{
// check user
var contextUser = context?.HttpContext?.User;
if (contextUser == null)
{
throw new BusinessException("Forbidden");
}
// check roles
var roles = contextUser.FindAll("http://schemas.microsoft.com/ws/2008/06/identity/claims/role").Select(c => c.Value).ToList();
if (!roles.Any(s => Claims.Contains(s)))
{
throw new BusinessException("Forbidden");
}
base.OnActionExecuting(context);
}
}
example
[CustomAuthorization(Claims = new string[]
{
nameof(AuthorizationRole.HR_ADMIN),
nameof(AuthorizationRole.HR_SETTING)
})]
[Route("api/[controller]")]
[ApiController]
public class SomeAdminController : ControllerBase
{
private readonly IMediator _mediator;
public SomeAdminController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet("list/SomeList")]
public async Task<IActionResult> SomeList()
=> Ok(await _mediator.Send(new SomeListQuery()));
}
That is Roles
public struct AuthorizationRole
{
public static string HR_ADMIN;
public static string HR_SETTING;
}
Here's a simple 5-step guide for how to implement custom role authorization using policies for all you copy and pasters out there :) . I used these docs.
Create a requirement:
public class RoleRequirement : IAuthorizationRequirement
{
public string Role { get; set; }
}
Create a handler:
public class RoleHandler : AuthorizationHandler<RoleRequirement>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
{
var requiredRole = requirement.Role;
//custom auth logic
// you can use context to access authenticated user,
// you can use dependecy injection to call custom services
var hasRole = true;
if (hasRole)
{
context.Succeed(requirement);
}
else
{
context.Fail(new AuthorizationFailureReason(this, $"Role {requirement.Role} missing"));
}
}
}
Add the handler in Program.cs:
builder.Services.AddSingleton<IAuthorizationHandler, RoleHandler>();
Add a policy with your role requirement in program.cs:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("Read", policy => policy.Requirements.Add(new RoleRequirement{Role = "ReadAccess_Custom_System"}));
});
Use your policy:
[Authorize("Read")]
public class ExampleController : ControllerBase
{
}
A lot of people here already told this, but with Policy handlers you can come really far in terms of what you could achieve with the old way in .NET Framework.
I followed a quick writeup from this answer on SO: https://stackoverflow.com/a/61963465/7081176
For me it works flawlessly after making some classes:
The EditUserRequirement:
public class EditUserRequirement : IAuthorizationRequirement
{
public EditUserRequirement()
{
}
}
An abstract handler to make my life easier:
public abstract class AbstractRequirementHandler<T> : IAuthorizationHandler
where T : IAuthorizationRequirement
{
public async Task HandleAsync(AuthorizationHandlerContext context)
{
var pendingRequirements = context.PendingRequirements.ToList();
foreach (var requirement in pendingRequirements)
{
if (requirement is T typedRequirement)
{
await HandleRequirementAsync(context, typedRequirement);
}
}
}
protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, T requirement);
}
An implementation of the abstract handler:
public class EditUserRequirementHandler : AbstractRequirementHandler<EditUserRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, EditUserRequirement requirement)
{
// If the user is owner of the resource, allow it.
if (IsOwner(context.User, g))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
private static bool IsOwner(ClaimsPrincipal user, Guid userIdentifier)
{
return user.GetUserIdentifier() == userIdentifier;
}
}
Registering my handler and requirement:
services.AddSingleton<IAuthorizationHandler, EditUserRequirementHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy(Policies.Policies.EditUser, policy =>
{
policy.Requirements.Add(new EditUserRequirement());
});
});
And then using my Policy in Blazor:
<AuthorizeView Policy="#Policies.EditUser" Resource="#id">
<NotAuthorized>
<Unauthorized />
</NotAuthorized>
<Authorized Context="Auth">
...
</Authorized>
</AuthorizeView>
I hope this is useful for anyone facing this issue.
I have been looking into solving a very similar issue, and settled on creating a custom ActionFilterAttribute (I'm going to call it AuthorizationFilterAttribute) instead of an AuthorizeAttribute to implement the guidance here: https://learn.microsoft.com/en-us/aspnet/core/security/authorization/resourcebased?view=aspnetcore-6.0#challenge-and-forbid-with-an-operational-resource-handler.
For authorization in our app. We had to call a service based on the parameters passed in authorization attribute.
For example, if we want to check if logged in doctor can view patient appointments we will pass "View_Appointment" to custom authorize attribute and check that right in DB service and based on results we will athorize. Here is the code for this scenario:
public class PatientAuthorizeAttribute : TypeFilterAttribute
{
public PatientAuthorizeAttribute(params PatientAccessRights[] right) : base(typeof(AuthFilter)) //PatientAccessRights is an enum
{
Arguments = new object[] { right };
}
private class AuthFilter : IActionFilter
{
PatientAccessRights[] right;
IAuthService authService;
public AuthFilter(IAuthService authService, PatientAccessRights[] right)
{
this.right = right;
this.authService = authService;
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
var allparameters = context.ActionArguments.Values;
if (allparameters.Count() == 1)
{
var param = allparameters.First();
if (typeof(IPatientRequest).IsAssignableFrom(param.GetType()))
{
IPatientRequest patientRequestInfo = (IPatientRequest)param;
PatientAccessRequest userAccessRequest = new PatientAccessRequest();
userAccessRequest.Rights = right;
userAccessRequest.MemberID = patientRequestInfo.PatientID;
var result = authService.CheckUserPatientAccess(userAccessRequest).Result; //this calls DB service to check from DB
if (result.Status == ReturnType.Failure)
{
//TODO: return apirepsonse
context.Result = new StatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
}
}
else
{
throw new AppSystemException("PatientAuthorizeAttribute not supported");
}
}
else
{
throw new AppSystemException("PatientAuthorizeAttribute not supported");
}
}
}
}
And on API action we use it like this:
[PatientAuthorize(PatientAccessRights.PATIENT_VIEW_APPOINTMENTS)] //this is enum, we can pass multiple
[HttpPost]
public SomeReturnType ViewAppointments()
{
}

Using ASP.NET Identity 2.2.1 with my own table in MVC

I installed identity 2.2.1 today. I created my own classes for Role, User, Claim, UserManager, UserRole, EmailService and SmsService. The above classes seem to be working.
I added a new class called SignInManager. I can't seem to fix the error message. I'm getting a convert error message.
public class MySignInManager : SignInManager<MyUser, long>
{
public MySignInManager(MyUserManager userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
}
Cannot implicitly convert type 'System.Threading.Tasks.Task' to 'System.Threading.Tasks.Task'
public override Task<MyClaim> CreateUserIdentityAsync(MyUser user)
{
return user.GenerateUserIdentityAsync((MyUserManager)UserManager);
}
This method is okay
public static MySignInManager Create(IdentityFactoryOptions<MySignInManager> options, IOwinContext context)
{
return new MySignInManager(context.GetUserManager<MyUserManager>(), context.Authentication);
}
The user Class looks like this:
public class MyUser : IdentityUser<long, MyLogin, MyUserRole, MyClaim>
{
public string ActivationToken { get; set; }
public string PasswordAnswer { get; set; }
public string PasswordQuestion { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(MyUserManager userManager)
{
var userIdentity = await userManager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
The method ends in Async, which is always a good indication that you need to use async semantics:
public async override Task<MyClaim> CreateUserIdentityAsync(MyUser user)
{
return await user.GenerateUserIdentityAsync((MyUserManager)UserManager);
}
i.e. add async to the method signature and await the result
I changed Task MyClaim to Task ClaimsIdentity to fix the problem.
public override Task<ClaimsIdentity> CreateUserIdentityAsync(PoseyUser user)
{
return user.GenerateUserIdentityAsync((PoseyUserManager)UserManager);
}

Categories