via net example based asp asp.net angularjs oauth asp.net-web-api claims-based-identity

asp.net - net - ¿Cómo puedo enviar información de autorización a mi aplicación cliente cuando uso AngularJS, WebAPI 2 y Oauth 2?



web api authentication (4)

Tengo una aplicación de cliente AngularJS que usa javascript (no coffeescript o mecanografiado) Oauth2 para autenticar contra una aplicación WebAPI 2 que utiliza la última Identity 2 . Todo el software en mi aplicación es el más reciente y se basa en this example . Los objetivos de mi navegador de cliente son IE9 y superiores.

Tenga en cuenta que hice algunos cambios menores en el ejemplo anterior porque no urlencode todos los datos enviados al servidor utilizando la transformación. En su lugar, urlencode solo en el método de autenticación a continuación:

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), };

Estoy desarrollando con VS2013 Actualización 2 y en el servidor, uso C #, el último Entity Framework y SQL Server 2012.

Para iniciar sesión, mi cliente llama a un método / Token a la WebAPI y le pasa el ID de usuario y la contraseña. El WebAPI luego responde con un token al cliente que almaceno. Con cada solicitud a WebAPI, el token se envía de vuelta y se autentica:

$http.defaults.headers.common.Authorization = ''Bearer '' + user.data.bearerToken;

Esto funciona muy bien hasta el momento, pero tal como está, la aplicación no puede distinguir entre los usuarios que tienen diferentes roles asignados a ellos.

Algunos de los métodos de WebAPI solo pueden ser ejecutados por usuarios que tienen un rol determinado. Me gustaría ajustar los menús de mi aplicación AngularJS frontal, de modo que solo si el usuario tiene esta función, los enlaces apropiados aparecerán visibles. Me doy cuenta de que esto no evitará que un usuario verifique el HTML y la publicación, pero no me preocupa, ya que seguiré teniendo la decoración del método para limitar la capacidad de los usuarios que no tienen un rol para realizar acciones.

¿Puede alguien darme un ejemplo de cómo puedo hacer esto utilizando solo el conjunto de productos mencionados anteriormente que menciono en la pregunta más JavaScript Web Tokens si ayudan a actualizar la solución? Por lo que entiendo, los roles son manejados por reclamos, pero no entiendo cómo agregarlos y enviarlos al cliente con tokens. Investigué mucho en internet, pero no he podido encontrar ningún buen ejemplo, ya que creo que la mayoría de esto es muy nuevo y no muchas personas han tenido la oportunidad de explorar cómo un SPA puede utilizar estos últimos programas. componentes.

Al responder a esta pregunta, tenga en cuenta que no estoy buscando una respuesta que pueda decirle a la comunidad cómo configurar roles en el servidor o una respuesta que explique qué tan importante es proporcionar controles de roles en el servidor. Creo que casi todos están conscientes de esto. Lo que realmente creo que será de utilidad es algunas sugerencias técnicas muy detalladas con un código de muestra y una explicación. Para mantener la respuesta enfocada, probablemente sea útil para todos si las respuestas que no cumplen con esta necesidad no se publican como respuestas sugeridas.

Gracias de antemano.


Aquí otra respuesta:

En ApplicationOAuthProvider.cs

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>(); ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password); if (user == null) { context.SetError("invalid_grant", "The user name or password is incorrect."); return; }

¡simplemente agrega un encabezado personalizado!

context.OwinContext.Response.Headers.Add("Roles", userManager.GetRoles(user.Id).ToArray());


Hay 2 formas en que veo que puede abordar su problema.

  1. incluya la información "Role" en el token mediante un hash o una cadena simple, ya que usted es el que genera el token, luego puede descifrarlo en el angular.

  2. parece que desea utilizar el sistema de identidad ASP.NET y almacenar y recuperar la información del rol allí. Si ese es el caso, puede revisar esta publicación y prestar atención a la sección "Inicializar la base de datos para crear el rol de administrador y el usuario administrador".

IMO, # 1 le dará más flexibilidad sobre cómo almacena y usa sus datos de usuario como # 2 usted está siguiendo el IdentityUser de Microsoft, aunque a veces parece mágico y tiende a publicar limitaciones y necesita dedicar tiempo para comprender cómo funciona detrás de él. la escena y haz que funcione para tu proyecto.

Para obtener más información sobre las "Cuentas de usuario individuales" que elige durante el proyecto de WebAPI que creó, puede acceder a http://www.asp.net/visual-studio/overview/2013/creating-web-projects-in-visual-studio#indauth


La respuesta breve a su pregunta es el método ApplicationOAuthProvider.CreateProperties . Se creó para usted de manera predeterminada y se encuentra en WebApi2 / Provider / ApplicationOAuthProvider.cs . De manera predeterminada, solo envía el nombre de 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); }

Haría la siguiente actualización (en caso de que necesite enviar más datos de usuario más adelante):

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); }

Si no ha realizado cambios importantes en el proyecto WebApi, ApplicationOAuthProvider.CreateProperties solo se referencia en dos lugares, simplemente actualice el código de llamada para pasar el oAuthIdentity junto con user.UserName y obtendrá las funciones del usuario enviadas junto con el acceso respuesta de token:

{ "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" }

Ahora que tiene los roles disponibles, puede usar directivas condicionales angulares para mostrar / ocultar acciones de acuerdo con los roles de los usuarios.

Si necesita más aclaración, hágamelo saber.

Editar:

Decorar sus métodos de controlador con el atributo Authorize es válido, ya que HttpContext.Current.User.Identity es en realidad una ClaimsIdentity . Pero como no es necesario codificar la lógica de seguridad dentro de la aplicación, prefiero usar ClaimsAuthorizationManager

public ActionResult Secure() { if(!ClaimsPrincipalPermission.CheckAccess("resource", "action")) return new HttpUnauthorizedResult(); ViewBag.Message = "You are allowed to perform action on resource."; return View(); }

Creación de roles usando RoleManager :

RoleManager roleManger = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>()); roleManager.Create(new IdentityRole() { Name = "Admin" });

Asignación de roles usando UserManager :

userManager.AddToRole(user.Id, "Admin");


Tengo un escenario muy similar al suyo, pero en lugar de usar tokens para autenticar, utilizo un servidor de identidad ( Thinktecture ) para manejar mi autenticación. Mi aplicación redirecciona al servidor de identidad para autenticarse y vuelve con algunas afirmaciones muy básicas (nombre de usuario y correo electrónico). Esto sucede tan pronto como alguien intenta navegar primero a la página. Una vez que el usuario es autenticado y redirigido a mi aplicación, realizo otra llamada al servidor para obtener los permisos del usuario. Estos permisos se almacenan dentro de un servicio de seguridad (AngularJS) que también expone un método "hasPermissions". Luego uso ng-si para decidir si voy a mostrar ciertas partes de la página, incluidos los elementos del menú. Algo a este efecto:

var service = { currentUser: ..., isAuthenticated: function() { return ...; }, checkAccess: function(permission) { return service.isAuthenticated() ? !!(service.currentUser.permissions.indexOf(permission) > -1) : false; } }

Recuerde que todos los permisos y elementos html son visibles para cualquiera que decida presionar el botón de herramientas de desarrollo y echar un vistazo. Debe hacer las mismas comprobaciones en el lado del servidor antes de realizar cualquier acción. Tenemos un atributo de Autorización personalizado basado en this que comprueba si el usuario tiene los permisos necesarios para ejecutar la acción MVC / WebAPI antes de que se ejecute para casos simples o realmente lo revisa dentro de la Acción o el recurso HTTP antes de hacer cualquier cosa que necesite elevada privilegios.

Si desea que el cliente no vea ningún elemento html o ciertas secciones de su sitio, puede apuntar sus plantillas a una acción MVC que se autenticará y luego devolver la plantilla HTML o redirigir a otra página (no el dominio SPA) y tenerlos autenticado en el servidor antes de que la respuesta sea devuelta.