Once I had the authentication part done I started working on the authorization. I wanted it to be role-based i.e. very similar to what you use by default in the default MVC model:
[Authorize(Roles = "Administrator")] public class AdminController : Controller { // Controller code here }In theory, if your Identity Provider issues a token containing the Identity Role claim (http://schemas.microsoft.com/ws/2008/06/identity/claims/role) with the value of user's current role the above default authorization code should work. And it actually does! This is because some basic claims from the token are automatically used to populate the user's identity object, including roles. So when your app's authorization code checks user's role it will use values provided in the token (if any were provided).
Membership database issue
The above solution worked fine for me at the beginning. What I was not aware of is the fact that, by default, theAuthorize
attribute also connects to you Membership database, regardless the token content. By default as membership database MVC uses the local ASPNETDB.mdf file. I realized that when I moved the application to a different server, without moving the mdf file. Suddenly I started getting the following SQL exception when calling the Authorize
attribute:
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)I guess there is an easy way to configure ASP not to connect to the database if roles are provided in the token. However, I decide to take a different approach to have more control over the code.
Custom authorization attribute
I decided to write a custom Authorization attribute, that would search for user's role directly in claims provided in the token:public class ClaimsAuthorizeAttribute : AuthorizeAttribute { private string claimType; private string claimValue; public ClaimsAuthorizeAttribute(string type, string value) { this.claimType = type; this.claimValue = value; } public override void OnAuthorization(AuthorizationContext filterContext) { var identity = (ClaimsIdentity)Thread.CurrentPrincipal.Identity; var claim = identity.Claims.FirstOrDefault(c => c.Type == claimType && c.Value == claimValue); if (claim != null) { base.OnAuthorization(filterContext); } else { base.HandleUnauthorizedRequest(filterContext); } } }This approach is more flexible as it allows me to use different types of claims for authorization in future, not only role. The usage of the attribute is still very simple:
[ClaimsAuthorize(ClaimTypes.Role, "Administrator")] public class AdminController : Controller { // Controller code here }
1 comment:
Why when we remove the roles authorize does not work automatically, because I need to log out and then a login for work? The problem is that the roles are stored in the cookie. I have to find some solution to update the cookie. When do I remove a roles directly in the database the cookie is outdated. I think I have update the cookie to each User request. The example I'm using is on github https://github.com/aspnet/Musi...
Post a Comment