I have a AngularJS
client application that uses javascript
(not coffeescript or typescript) Oauth2 to authenticate against a WebAPI 2
application using the latest Identity 2
. All the software in my application is the very latest and is based on this example
. My client browser targets are IE9 and above.
Note that I made some minor changes from the example above in that I do not urlencode all of the data sent to the server using the transform. Instead I urlencode only in the authenticate method below:
user.authenticate = function (userName, password, rememberMe, successCallback, errorCallback) { var config = { method: 'POST', url: '/Token', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, data: 'grant_type=password&username=' + encodeURIComponent(userName) + '&password=' + encodeURIComponent(password), };
I am developing with VS2013 Update 2 and on the server, I use C#, the latest Entity Framework and SQL Server 2012.
To login my client calls a /Token method to the WebAPI and passes the userid and password. The WebAPI then responds with a token to the client which I store. With each request to the WebAPI the token is sent back and authenticated:
$http.defaults.headers.common.Authorization = 'Bearer ' + user.data.bearerToken;
This works very well so far but as it stands the application is unable to tell the difference between users that have different roles assigned to them.
Some of the WebAPI methods can only be executed by users who have a certain role. I would like to adjust the menus of my front-end AngularJS application so that only if the user has this role then the appropriate links will appear visible. I do realize that this would not stop a user from checking the HTML and posting but I am not concerned about this as I will still have method decoration to limit the ability of users not in a role to perform actions.
Can someone give me an example of how I can do this using just the suite of products mentioned above that I mention in the question plus JavaScript Web Tokens if they help make bring the solution up to date. From what I understand roles are handled by claims but I do not understand how to add these and send them back to the client with tokens. I have done a lot of research on the internet but I've not been able to find any good examples as I think most of this is very new and not many people have had the chance to explore how a SPA can use these very latest software components.
When answering this question please note that I am not looking for an answer that can tell the community how to set up roles on the server or an answer that explains about how important it is to provide role checks on the server. I think almost everyone is aware of this. What I really think will be of use is some very detailed technical suggestions with sample code and an explanation. To keep the answer focused it would probably be of help to everyone if answers that do not meet this need are not posted as suggested answers.
Thank you in advance.
OAuth 2.0, which stands for “Open Authorization”, is a standard designed to allow a website or application to access resources hosted by other web apps on behalf of a user. It replaced OAuth 1.0 in 2012 and is now the de facto industry standard for online authorization.
The OAuth 2.0 client credentials grant flow permits a web service (confidential client) to use its own credentials, instead of impersonating a user, to authenticate when calling another web service.
Custom URI scheme (Android, iOS, UWP) A custom URI scheme is recommended for Android apps, iOS apps, and Universal Windows Platform (UWP) apps.
OAuth doesn't share password data but instead uses authorization tokens to prove an identity between consumers and service providers. OAuth is an authentication protocol that allows you to approve one application interacting with another on your behalf without giving away your password.
The short answer to your question is ApplicationOAuthProvider.CreateProperties
method. Its created for you by default and is found under WebApi2/Provider/ApplicationOAuthProvider.cs, By default it only sends the userName
//WepApi2/Providers/ApplicationOAuthProvider.cs public static AuthenticationProperties CreateProperties(string userName) { IDictionary<string, string> data = new Dictionary<string, string> { { "userName", userName } }; return new AuthenticationProperties(data); }
I would make the following update (in case I need to send more user data later on):
public static AuthenticationProperties CreateProperties(string userName, ClaimsIdentity oAuthIdentity) { IDictionary<string, string> data = new Dictionary<string, string> { { "userName", userName}, { "roles",string.Join(",",oAuthIdentity.Claims.Where(c=> c.Type == ClaimTypes.Role).Select(c => c.Value).ToArray())} }; return new AuthenticationProperties(data); }
If you haven't made major changes to the WebApi project, ApplicationOAuthProvider.CreateProperties
is only referenced in two places, just update the calling code to pass the oAuthIdentity
along with user.UserName
and you'll get the user roles sent along with the access token response:
{ "access_token": "ZpxAZyYuvCaWgShUz0c_XDLFqpbC0-DIeXl_tuFbr11G-5hzBzSUxFNwNPahsasBD9t6mDDJGHcuEqdvtBT4kDNQXFcjWYvFP7U2Y0EvLS3yejdSvUrh2v1N7Ntz80WKe5G_wy2t11eT0l48dgdyak8lYcl3Nx8D0cgwlQm-pePIanYZatdPFP9q5jzhD-_k9SF-ARTHgf0ePnbvhLBi1MCYQjvfgPKlbBHt0M5qjwGAeFg1IhSVj0gb4g9QTXoiPhRmxGBmjOpGgzxXixavmrpM7cCBFLoR3DCGnIJo6pwT-6VArxlB8-ZyyOZqh_6gGtptd0lIu8iJRUIGwO9HFNkROdoE9T4buwLnhPpWpy9geBjPVwsB1K3xnbch26YbklhxIHVybBxeIVXd17QTw_LjlQ5TJdqpAYfiZ5B9Nx2AFYYYe3--aemh4y1XOIvN", "token_type": "bearer", "expires_in": 1209599, "userName": "MK", "roles": "Admin,Public", ".issued": "Fri, 23 May 2014 17:36:54 GMT", ".expires": "Fri, 06 Jun 2014 17:36:54 GMT" }
Now you have the roles available, you can use Angular conditional directives to show/hide actions according to user roles.
If you need more clarification, please let me know.
Edit:
Decorating your controller methods with Authorize
attribute is valid, since the HttpContext.Current.User.Identity
is actually a ClaimsIdentity
. But as not to hard code security logic inside the application, I prefer using ClaimsAuthorizationManager
public ActionResult Secure() { if(!ClaimsPrincipalPermission.CheckAccess("resource", "action")) return new HttpUnauthorizedResult(); ViewBag.Message = "You are allowed to perform action on resource."; return View(); }
Roles creation using RoleManager
:
RoleManager roleManger = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>()); roleManager.Create(new IdentityRole() { Name = "Admin" });
Roles assignment using UserManager
:
userManager.AddToRole(user.Id, "Admin");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With