net example based asp c# authentication token owin

c# - example - Autentificación de token de portador de Owin+Autorizar controlador



web api authentication token example (4)

Bueno, he estado trabajando en esto por algún tiempo y finalmente me di cuenta de lo que está mal y ahora está funcionando.

Parece que el código de habilitación de Cors en el método GrantResourceOwnerCredentials está anulando de alguna manera el encabezado del parámetro. Entonces, al poner su primera línea justo debajo de su tercera actual, tendrá su problema resuelto:

var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>(); IdentityUser user = await userManager.FindAsync(context.UserName, context.Password); context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

Hasta ahora no he profundizado más para comprender por qué esto es así, pero creo que al agregar la nueva entrada del encabezado antes de que el Administrador de usuarios corrompa de alguna manera los datos que el método de envío está enviando al cliente, en mi caso, un Recurso angular que va así:

function userAccount($resource, appSettings) { return { registration: $resource(appSettings.serverPath + "/api/Account/Register", null, { ''registerUser'' : { method : ''POST''} } ), login : $resource(appSettings.serverPath + "/Token", null, { ''loginUser'': { method: ''POST'', headers: { ''Content-Type'' : ''application/x-www-form-urlencoded'' }, transformRequest: function (data, headersGetter) { var str = []; for (var d in data) { str.push(encodeURIComponent(d) + "=" + encodeURIComponent(data[d])); } return str.join("&"); } } } ) } }

Estoy tratando de hacer autenticación con tokens de Bearer y owin.

Puedo emitir la multa de token utilizando la password tipo de concesión y anulando GrantResourceOwnerCredentials en AuthorizationServerProvider.cs .

Pero no puedo alcanzar un método de controlador con el atributo Authorize .

Aquí está mi código:

Startup.cs

public class Startup { public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; } // normal public Startup() : this(false) { } // testing public Startup(bool isDev) { // add settings Settings.Configure(isDev); OAuthOptions = new OAuthAuthorizationServerOptions { AllowInsecureHttp = true, TokenEndpointPath = new PathString("/Token"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), Provider = new AuthorizationServerProvider() }; } public void Configuration(IAppBuilder app) { // Configure the db context, user manager and role manager to use a single instance per request app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create); app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create); app.CreatePerOwinContext<LoanManager>(BaseManager.Create); var config = new HttpConfiguration(); WebApiConfig.Register(config); app.UseWebApi(config); // token generation app.UseOAuthAuthorizationServer(OAuthOptions); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions { AuthenticationType = "Bearer", AuthenticationMode = AuthenticationMode.Active }); } }

AuthorizationServerProvider.cs

public class AuthorizationServerProvider : OAuthAuthorizationServerProvider { public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { context.Validated(); } public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>(); IdentityUser user = await userManager.FindAsync(context.UserName, context.Password); if (user == null) { context.SetError("invalid_grant", "The user name or password is incorrect."); return; } var identity = new ClaimsIdentity(context.Options.AuthenticationType); identity.AddClaim(new Claim("sub", context.UserName)); identity.AddClaim(new Claim("role", "user")); context.Validated(identity); } }

WebApiConfig.cs

public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.MapHttpAttributeRoutes(); // enable CORS for all hosts, headers and methods var cors = new EnableCorsAttribute("*", "*", "*"); config.EnableCors(cors); config.Routes.MapHttpRoute( name: "optional params", routeTemplate: "api/{controller}" ); config.Routes.MapHttpRoute( name: "Default", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); // stop cookie auth config.SuppressDefaultHostAuthentication(); // add token bearer auth config.Filters.Add(new MyAuthenticationFilter()); //config.Filters.Add(new HostAuthenticationFilter(Startup.OAuthOptions.AuthenticationType)); config.Filters.Add(new ValidateModelAttribute()); if (Settings.IsDev == false) { config.Filters.Add(new AuthorizeAttribute()); } // make properties on model camelCased var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First(); jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html")); }

MyAuthenticationFilter.cs Filtro personalizado usado para propósitos de depuración

public class MyAuthenticationFilter : ActionFilterAttribute, IAuthenticationFilter { public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) { if (context.Principal != null && context.Principal.Identity.IsAuthenticated) { } return Task.FromResult(0); } public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken) { throw new System.NotImplementedException(); } }

Si depuro AuthenticateAsync en MyAuthenticationFilter.cs veo el encabezado en la solicitud:

Authorization: Bearer AQAAANCMnd8BFdERjHoAwE_Cl...

Pero los reclamos de identidad están vacíos y context.Principal.Identity.IsAuthenticated es falso.

¿Algunas ideas?


Estaba buscando la misma solución, pasé una semana más o menos en esto y la dejé. Hoy comencé a buscar nuevamente, encontré sus preguntas y esperaba encontrar una respuesta.

Así que pasé todo el día haciendo otra cosa que no fuera probar todas las soluciones posibles, fusionando sugerencias entre sí, encontré alguna solución, pero eran largas soluciones, para resumir la larga historia aquí es lo que encontré.

En primer lugar, si necesita autenticar el sitio web con un token de proveedor de identidad de terceros personalizado, debe tener ambos usando la misma clave de la máquina o tenerlos en el mismo servidor.

Debe agregar el machineKey a la sección system.web siguiente manera:

Web.Config

<system.web> <authentication mode="None" /> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5" /> <machineKey validationKey="*****" decryptionKey="***" validation="SHA1" decryption="AES" /> </system.web>

Aquí hay un enlace para generar un nuevo machineKey :

Ahora necesita moverse al archivo Startup.Auth.cs donde puede encontrar la clase parcial Startup.cs, necesita definir el OAuthBearerOptions

Startup.Auth.cs

public partial class Startup { public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; } ... public void ConfigureAuth(IAppBuilder app) { // Configure the db context, user manager and signin manager to use a single instance per request app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); OAuthBearerOptions = new OAuthBearerAuthenticationOptions(); app.UseOAuthBearerAuthentication(OAuthBearerOptions); ... } }

Reemplace su acción de inicio de sesión dentro de AccountController con lo siguiente:

AccountController.cs

[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { /*This will depend totally on how you will get access to the identity provider and get your token, this is just a sample of how it would be done*/ /*Get Access Token Start*/ HttpClient httpClient = new HttpClient(); httpClient.BaseAddress = new Uri("https://youridentityproviderbaseurl"); var postData = new List<KeyValuePair<string, string>>(); postData.Add(new KeyValuePair<string, string>("UserName", model.Email)); postData.Add(new KeyValuePair<string, string>("Password", model.Password)); HttpContent content = new FormUrlEncodedContent(postData); HttpResponseMessage response = await httpClient.PostAsync("yourloginapi", content); response.EnsureSuccessStatusCode(); string AccessToken = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync()); /*Get Access Token End*/ If(!string.IsNullOrEmpty(AccessToken)) { var ticket = Startup.OAuthBearerOptions.AccessTokenFormat.Unprotect(AccessToken); var id = new ClaimsIdentity(ticket.Identity.Claims, DefaultAuthenticationTypes.ApplicationCookie); AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = true }, id); return RedirectToLocal(returnUrl); } ModelState.AddModelError("Error", "Invalid Authentication"); return View(); }

Lo último que debe hacer es colocar esta línea de código en Global.asax.cs para evitar excepciones de Anti-falsificación:

Global.asax.cs

public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier; … } }

Espero que esto funcione para usted.


No estoy seguro de si esto ayuda, pero tuve un problema con IsAuthenticated que devolvía el estado falso mientras utilizaba la inyección de dependencia (vea la pregunta de SO here ) y lo detecté porque en el punto de la inyección no había sido establecido por la tubería de Owin.

Lo superé por perezoso inyectando al director. De cualquier manera, armé una aplicación realmente básica (que está vinculada a la anterior) para demostrar el problema, pero podría ayudarlo ya que muestra que el Principal está configurado en el atributo y el uso de la autenticación del portador.


Un año desde que se publicó, y yo también experimenté el mismo problema.

Como puede ver, mi token de portador se reconoce en los encabezados de solicitud, pero mi identidad aún no se puede autenticar.

Para solucionarlo, la respuesta corta es asegurarse de configurar su middleware OAuth antes de configurar su middleware WebApi (Configuración HTTP).