Reputation: 1039
So I'm trying to create a custom authorisation system which supports my custom token in my ASP.NET core web API. I know how to create custom handlers and all but I don't know one thing, I even don't know if it's even possible, how can I read the Role attribute from:
[Authorize(Roles="role")]
this is my custom authorisation handler:
public class Auth : AuthenticationHandler<AuthOptions>
{
//private static Models.flowerpowerContext context = new Models.flowerpowerContext
private Token.AuthToken authToken;
private readonly RequestDelegate _next;
private Models.flowerpowerContext _context;
public Auth(IOptionsMonitor<AuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
DbContextOptions<Models.flowerpowerContext> _options = new DbContextOptions<Models.flowerpowerContext>();
_context = new Models.flowerpowerContext(_options);
string test = options.ToString();
authToken = new Token.AuthToken(_context);
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
Models.Token _token = new Models.Token();
Token.Hasher hasher = new Token.Hasher();
var bearer = Request.Headers["Authorization"];
string token = bearer.ToString();
_token = JsonConvert.DeserializeObject<Models.Token>(hasher.DecodeHash(token));
string id = "";
return AuthenticateResult.NoResult();
}
}
The above handler works fine and it get's the token from the Authorization header. And the AuthOptions only have an empty constructor.
I couldn't find anything that would seem, at least to me, to retrieve the value of the Roles parameter. Does anybody know a better approach/work-around or a direct solution to this, and also if this is even possible?
EDIT: Forgot to mention why I want to do this; I want to do this because the role of the user has been defined within my custom token. And I need to compare it to the required role.
Upvotes: 1
Views: 1935
Reputation: 1039
So after I followed CodeFuller's responses I came up with a solution. I basically I had to create a Claim collection like this:
IList<Claim> claimCollection = new List<Claim>
{
new Claim(ClaimTypes.Email, _token.TokenEmail),
new Claim(ClaimTypes.Role, _token.TokenRole)
};
Then I had to appoint a ClaimsIdentity and a ClaimsPrinciple. After this I had to create an AuthenticationTicket like this:
AuthenticationTicket ticket = new AuthenticationTicket(principal, "Custom scheme");
And all I had to do now was to return this:
return AuthenticateResult.Success(ticket);
This allowed me to verify roles from my custom token. This basically allowed me to do this:
[Authorize(Roles = "Admin")]
To get some more explanation about this matter you should check out CodeFuller's response.
Upvotes: 3
Reputation: 31312
You mix up two concepts here, authentication and authorization.
Authentication is the process of verifying who the user is.
Authorization is the process of verifying that the user has the access to requested resource.
Your Auth
class is responsible for authentication, not authorization. If request is successfully authenticated, HandleAuthenticateAsync
method should return instance of AuthenticateResult
with filled Principal
property of ClaimsPrincipal
type. ClaimsPrincipal
implements IPrincipal
interface that has method bool IsInRole(string role)
.
Thus after the authentication step, it's known for the principal associated with the request, whether hi is in specific role. And the list of roles authorized for specific controller or action is specified in Roles
property of AuthorizeAttribute
. In your example if request principal is in "role", request will be successfully authorized. If he is not, request will fail with 401 or 403 error. This code of checking principal role is already implemented in AuthorizeAttribute
filter. You don't need to reinvent it until you implement your custom authorization filter (I remind you that your Auth
class is an authentication filter).
So answering your question about handling the user role: you should just return proper principal object that returns correct value for IsInRole(string role)
method. All the rest will be handled by default authorization filter.
Upvotes: 3