net example bearer based asp asp.net-web-api oauth-2.0 asp.net-mvc-5 owin asp.net-identity

asp.net web api - example - API web 2 OWIN Autenticación del token del portador-AccessTokenFormat null?



web api authentication token example c# (3)

Tengo un proyecto ASP.NET MVC 5 existente y le estoy agregando un proyecto Web API 2. Deseo utilizar la autenticación de token de portador y he seguido el tutorial de Hongye Sun "Autenticación de token de portador OWIN con muestra de API web" y esta pregunta también.

En mi método de Login , para la línea Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket); , AccessTokenFormat es nulo. ¿Alguna idea de por qué?

Mi AccountController :

[RoutePrefix("api")] public class AccountController : ApiController { public AccountController() {} // POST api/login [HttpPost] [Route("login")] public HttpResponseMessage Login(int id, string pwd) { if (id > 0) // testing - not authenticating right now { var identity = new ClaimsIdentity(Startup.OAuthBearerOptions.AuthenticationType); identity.AddClaim(new Claim(ClaimTypes.Name, id.ToString())); AuthenticationTicket ticket = new AuthenticationTicket(identity, new AuthenticationProperties()); var currentUtc = new SystemClock().UtcNow; ticket.Properties.IssuedUtc = currentUtc; ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromMinutes(30)); var token = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket); return new HttpResponseMessage(HttpStatusCode.OK) { Content = new ObjectContent<object>(new { UserName = id.ToString(), AccessToken = token }, Configuration.Formatters.JsonFormatter) }; } return new HttpResponseMessage(HttpStatusCode.BadRequest); } // POST api/token [Route("token")] [HttpPost] public HttpResponseMessage Token(int id, string pwd) { // Never reaches here. Do I need this method? return new HttpResponseMessage(HttpStatusCode.OK); } }

Clase de inicio :

public class Startup { private static readonly ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; } public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; } public static Func<MyUserManager> UserManagerFactory { get; set; } public static string PublicClientId { get; private set; } static Startup() { PublicClientId = "MyWeb"; UserManagerFactory = () => new MyUserManager(new UserStore<MyIdentityUser>()); OAuthBearerOptions = new OAuthBearerAuthenticationOptions(); OAuthOptions = new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/api/token"), Provider = new MyWebOAuthProvider(PublicClientId, UserManagerFactory), AuthorizeEndpointPath = new PathString("/api/login"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(14), AllowInsecureHttp = true }; } public void Configuration(IAppBuilder app) { // Enable the application to use bearer tokens to authenticate users app.UseOAuthBearerTokens(OAuthOptions); app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/api/login") }); // Configure Web API to use only bearer token authentication. var config = GlobalConfiguration.Configuration; config.SuppressDefaultHostAuthentication(); config.Filters.Add(new HostAuthenticationFilter(OAuthBearerOptions.AuthenticationType)); app.UseWebApi(config); } }

MyIdentityUser solo agrega una propiedad extra:

public class MyIdentityUser : IdentityUser { public int SecurityLevel { get; set; } }

MyUserManager llama a mi método de autenticación de usuario personalizado a un servidor interno:

public class MyUserManager : UserManager<MyIdentityUser> { public MyUserManager(IUserStore<MyIdentityUser> store) : base(store) { } public MyIdentityUser ValidateUser(int id, string pwd) { LoginIdentityUser user = null; if (MyApplication.ValidateUser(id, pwd)) { // user = ??? - not yet implemented } return user; } }

MyWebOAuthProvider (tomé esto de la plantilla SPA. Solo GrantResourceOwnerCredentials ha sido cambiado):

public class MyWebOAuthProvider : OAuthAuthorizationServerProvider { private readonly string _publicClientId; private readonly Func<MyUserManager> _userManagerFactory; public MyWebOAuthProvider(string publicClientId, Func<MyUserManager> userManagerFactory) { if (publicClientId == null) { throw new ArgumentNullException("publicClientId"); } if (userManagerFactory == null) { throw new ArgumentNullException("userManagerFactory"); } _publicClientId = publicClientId; _userManagerFactory = userManagerFactory; } public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { using (MyUserManager userManager = _userManagerFactory()) { MyIdentityUser user = null; var ctx = context as MyWebOAuthGrantResourceOwnerCredentialsContext; if (ctx != null) { user = userManager.ValidateUser(ctx.Id, ctx.Pwd); } if (user == null) { context.SetError("invalid_grant", "The user name or password is incorrect."); return; } ClaimsIdentity oAuthIdentity = await userManager.CreateIdentityAsync(user, context.Options.AuthenticationType); ClaimsIdentity cookiesIdentity = await userManager.CreateIdentityAsync(user, CookieAuthenticationDefaults.AuthenticationType); AuthenticationProperties properties = CreateProperties(user.UserName); AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties); context.Validated(ticket); context.Request.Context.Authentication.SignIn(cookiesIdentity); } } public override Task TokenEndpoint(OAuthTokenEndpointContext context) { ... // unchanged from SPA template } public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { ... // unchanged from SPA template } public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context) { ... // unchanged from SPA template } public static AuthenticationProperties CreateProperties(string userName) { ... // unchanged from SPA template } }

MyWebOAuthGrantResourceOwnerCredientialsContext :

public class MyWebOAuthGrantResourceOwnerCredentialsContext : OAuthGrantResourceOwnerCredentialsContext { public MyWebOAuthGrantResourceOwnerCredentialsContext (IOwinContext context, OAuthAuthorizationServerOptions options, string clientId, string userName, string password, IList<string> scope) : base(context, options, clientId, userName, password, scope) { } public int Id { get; set; } public string Pwd { get; set; } }

¿Cómo se configura AccessTokenFormat ? Es lo que he configurado correcto? No estoy autenticando contra ningún servicio externo, solo un servidor interno heredado. Gracias.


He eliminado el código de muestra, ya que puede causar confusión cuando se usa con la API web y la plantilla SPA. Es mejor que se quede con el código de la plantilla para usar el servidor de autorización OAuth para generar el token. En su escenario, debe usar la concesión de contraseña del propietario del recurso para autenticar al usuario. Por favor revisa mi blog en la plantilla SPA que tiene detalles sobre el flujo de contraseñas en http://blogs.msdn.com/b/webdev/archive/2013/09/20/understanding-security-features-in-spa-template.aspx

En lugar de escribir su propia API web para manejar el inicio de sesión, debe usar el punto final OWIN OAuth Server / token para manejar el inicio de sesión con contraseña.


No estoy seguro de si todavía está buscando la respuesta a esto, pero aquí hay un poco de código que estoy usando en mi aplicación AngularJS para obtener el token de seguridad de mi punto final WebAPI2.

$http({ method: ''POST'', url: ''/token'', data: { username: uName, password: uPassword, grant_type: ''password'' }, transformRequest: function (obj) { var str = []; for (var p in obj) str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); return str.join("&"); } }).success(function (data, status, headers, config) { console.log("http success", data); accessToken.value = data.access_token; console.log("access token = ", accessToken.value); }).error(function (data, status, headers, config) { console.log("http error", data); });

Luego puedo pasar el accessToken en el encabezado de cualquier otra solicitud para obtener la validación de la autenticación.


Tuve el mismo problema: tenía que ver con mi inicialización en Startup ().

Al igual que usted, estaba almacenando OAuthBearerOptions en un campo estático:

OAuthBearerOptions = new OAuthBearerAuthenticationOptions();

Pero luego usé erróneamente una nueva instancia de la misma clase más adelante:

app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); // wrong!

Obviamente, la solución fue usar el campo estático en su lugar:

app.UseOAuthBearerAuthentication(OAuthBearerOptions);

De hecho, no parece que llame a UseOAuthBearerAuthentication () en absoluto. Seguí esta excelente serie de publicaciones de Taiseer Joudeh.

Inicio completo.cs:

public class Startup { public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; } public void Configuration(IAppBuilder app) { HttpConfiguration config = new HttpConfiguration(); ConfigureOAuth(app); WebApiConfig.Register(config); app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); app.UseWebApi(config); } public void ConfigureOAuth(IAppBuilder app) { //use a cookie to temporarily store information about a user logging in with a third party login provider app.UseExternalSignInCookie(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ExternalCookie); OAuthBearerOptions = new OAuthBearerAuthenticationOptions(); OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() { AllowInsecureHttp = true, TokenEndpointPath = new PathString("/token"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), Provider = new SimpleAuthorizationServerProvider() // see post }; // Token Generation app.UseOAuthAuthorizationServer(OAuthServerOptions); app.UseOAuthBearerAuthentication(OAuthBearerOptions); //[Configure External Logins...] } }