c# - implement - web api authentication token example
Devuelve más información al cliente usando OAuth Bearer Tokens Generation y Owin en WebApi (2)
Creé una aplicación WebApi y una aplicación Cordova. Estoy usando solicitudes HTTP para comunicarme entre la aplicación Cordova y la WebAPI. En la WebAPI, he implementado Generación de Token de Portador OAuth.
public void ConfigureOAuth(IAppBuilder app)
{
var oAuthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider(new UserService(new Repository<User>(new RabbitApiObjectContext()), new EncryptionService()))
};
// Token Generation
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
y esto está dentro de la implementación SimpleAuthorizationServerProvider
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
// A little hack. context.UserName contains the email
var user = await _userService.GetUserByEmailAndPassword(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "Wrong email or password.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
después de una solicitud de inicio de sesión exitosa a la API desde la aplicación Cordova, recibo el siguiente JSON
{"access_token":"some token","token_type":"bearer","expires_in":86399}
El problema es que necesito más información sobre el usuario. Por ejemplo, tengo un campo UserGuid en la base de datos y deseo enviarlo a la aplicación Cordova cuando el inicio de sesión sea exitoso y usarlo más adelante en otras solicitudes. ¿Puedo incluir otra información para devolver al cliente, que no sea "access_token", "token_type"
y "expires_in"
? Si no, ¿cómo puedo obtener el usuario en la API en función de access_token
?
EDITAR:
Creo que encontré una solución. GrantResourceOwnerCredentials
el siguiente código dentro de GrantResourceOwnerCredentials
identity.AddClaim(new Claim(ClaimTypes.Name, user.UserGuid.ToString()));
y después de eso, User.Identity.Name
al GUID dentro de mi controlador de esta manera: User.Identity.Name
También puedo agregar el guid con un nombre personalizado identity.AddClaim(new Claim("guid", user.UserGuid.ToString()));
Todavía estoy interesado en saber si hay una forma de devolver más datos al cliente con el token JSON portador.
Mi recomendación es no agregar reclamos adicionales al token si no es necesario, porque aumentará el tamaño del token y seguirá enviándolo con cada solicitud. Como LeftyX aconseja agregarlos como propiedades, asegúrese de anular el método TokenEndPoint
para obtener esas propiedades como respuesta cuando obtenga el token con éxito, sin este punto final las propiedades no volverán en la respuesta.
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
Puede consultar mi informe aquí para ver un ejemplo completo. Espero que ayude
Puede agregar tantas reclamaciones como desee.
Puede agregar el conjunto estándar de System.Security.Claims
de System.Security.Claims
o crear el suyo propio.
Las afirmaciones se cifrarán en su token, por lo que solo se accederá a ellas desde el servidor de recursos.
Si desea que su cliente pueda leer las propiedades extendidas de su token, tiene otra opción: AuthenticationProperties
.
Digamos que desea agregar algo para que su cliente pueda tener acceso a. Ese es el camino a seguir:
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{
"surname", "Smith"
},
{
"age", "20"
},
{
"gender", "Male"
}
});
Ahora puede crear un ticket con las propiedades que ha agregado arriba:
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
Ese es el resultado que obtendrá su cliente:
.expires: "Tue, 14 Oct 2014 20:42:52 GMT"
.issued: "Tue, 14 Oct 2014 20:12:52 GMT"
access_token: "blahblahblah"
expires_in: 1799
age: "20"
gender: "Male"
surname: "Smith"
token_type: "bearer"
Por otro lado, si agrega reclamos, podrá leerlos en su servidor de recursos en su controlador API:
public IHttpActionResult Get()
{
ClaimsPrincipal principal = Request.GetRequestContext().Principal as ClaimsPrincipal;
return Ok();
}
Su ClaimsPrincipal
contendrá el nuevo guid
de reclamo que ha agregado aquí:
identity.AddClaim(new Claim("guid", user.UserGuid.ToString()));
Si quiere saber más sobre owin, tokens de portador y api web, aquí hay un buen tutorial y este article lo ayudará a comprender todos los conceptos detrás de Authorization Server y Resource Server .
ACTUALIZAR :
Puedes encontrar un ejemplo de trabajo here . Este es un Web Api + Owin autohospedado .
No hay una base de datos involucrada aquí. El cliente es una aplicación de consola (también hay una muestra html + JavaScript) que llama a una API web que pasa credenciales.
Como sugirió Taiseer, debes anular TokenEndpoint
:
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
Habilite ''Multiple Startup Projects'' desde Solution -> Properties y podrá ejecutarlo de inmediato.