web-dev-qa-db-fra.com

Obtenez IPrincipal de OAuth Token porteur dans OWIN

J'ai ajouté avec succès OAuth à mon projet WebAPI 2 en utilisant OWIN. Je reçois des jetons et je peux les utiliser dans l'en-tête HTTP pour accéder aux ressources.

Maintenant, je veux utiliser ces jetons également sur d'autres canaux d'authentification qui ne sont pas les requêtes HTTP standard pour lesquelles le modèle OWIN est fait. Par exemple, j'utilise WebSockets où le client doit envoyer le OAuth Token porteur pour s'authentifier.

Côté serveur, je reçois le jeton via le WebSocket. Mais comment puis-je maintenant mettre ce jeton dans le pipeline OWIN pour en extraire IPrincipal et ClientIdentifier? Dans le modèle WebApi 2, tout cela est abstrait pour moi, donc je n'ai rien à faire pour fais-le fonctionner.

Donc, fondamentalement, J'ai le jeton sous forme de chaîne et je veux utiliser OWIN pour accéder aux informations utilisateur encodées dans ce jeton.

Merci d'avance pour votre aide.

30
Sebastian Rösch

J'ai trouvé une partie de la solution dans cet article de blog: http://leastprivilege.com/2013/10/31/retrieving-bearer-tokens-from-alternative-locations-in-katanaowin/

J'ai donc créé mon propre fournisseur comme suit:

public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider
{
    public override Task RequestToken(OAuthRequestTokenContext context)
    {
        var value = context.Request.Query.Get("access_token");

        if (!string.IsNullOrEmpty(value))
        {
            context.Token = value;
        }

        return Task.FromResult<object>(null);
    }
}

Ensuite, je devais l'ajouter à mon application dans Startup.Auth.cs comme ceci:

OAuthBearerOptions = new OAuthBearerAuthenticationOptions()
{
   Provider = new QueryStringOAuthBearerProvider(),
   AccessTokenProvider = new AuthenticationTokenProvider()
   {
       OnCreate = create,
       OnReceive = receive
   },
};

app.UseOAuthBearerAuthentication(OAuthBearerOptions);

Avec un AuthenticationTokenProvider personnalisé, je peux récupérer toutes les autres valeurs du jeton au début du pipeline:

public static Action<AuthenticationTokenCreateContext> create = new Action<AuthenticationTokenCreateContext>(c =>
{
    c.SetToken(c.SerializeTicket());
});

public static Action<AuthenticationTokenReceiveContext> receive = new Action<AuthenticationTokenReceiveContext>(c =>
{
    c.DeserializeTicket(c.Token);
    c.OwinContext.Environment["Properties"] = c.Ticket.Properties;
});

Et maintenant, par exemple dans mon WebSocket Hander, je peux récupérer ClientId et d'autres comme ceci:

IOwinContext owinContext = context.GetOwinContext();
if (owinContext.Environment.ContainsKey("Properties"))
{
    AuthenticationProperties properties = owinContext.Environment["Properties"] as AuthenticationProperties;
    string clientId = properties.Dictionary["clientId"];
...
 }
28
Sebastian Rösch

Par défaut, OWIN utilise la protection des données de la clé machine ASP.NET pour protéger le jeton d'accès OAuth lorsqu'il est hébergé sur IIS. Vous pouvez utiliser la classe MachineKey dans System.Web.dll pour déprotéger les jetons.

public class MachineKeyProtector : IDataProtector
{
    private readonly string[] _purpose =
    {
        typeof(OAuthAuthorizationServerMiddleware).Namespace,
        "Access_Token",
        "v1"
    };

    public byte[] Protect(byte[] userData)
    {
       throw new NotImplementedException();
    }

    public byte[] Unprotect(byte[] protectedData)
    {
        return System.Web.Security.MachineKey.Unprotect(protectedData, _purpose);
    }
}

Ensuite, créez un TicketDataFormat pour obtenir l'objet AuthenticationTicket où vous pouvez obtenir les ClaimsIdentity et AuthenticationProperties.

var access_token="your token here";
var secureDataFormat = new TicketDataFormat(new MachineKeyProtector());
AuthenticationTicket ticket = secureDataFormat.Unprotect(access_token);

Pour déprotéger d'autres jetons OAuth, il vous suffit de modifier le contenu _purpose. Pour plus d'informations, consultez la classe OAuthAuthorizationServerMiddleware ici: http://katanaproject.codeplex.com/SourceControl/latest # src/Microsoft.Owin.Security.OAuth/OAuthAuthorizationServerMiddleware.cs

if (Options.AuthorizationCodeFormat == null)
{
    IDataProtector dataProtecter = app.CreateDataProtector(
        typeof(OAuthAuthorizationServerMiddleware).FullName,
        "Authentication_Code", "v1");

    Options.AuthorizationCodeFormat = new TicketDataFormat(dataProtecter);
}
if (Options.AccessTokenFormat == null)
{
    IDataProtector dataProtecter = app.CreateDataProtector(
        typeof(OAuthAuthorizationServerMiddleware).Namespace,
        "Access_Token", "v1");
    Options.AccessTokenFormat = new TicketDataFormat(dataProtecter);
}
if (Options.RefreshTokenFormat == null)
{
    IDataProtector dataProtecter = app.CreateDataProtector(
        typeof(OAuthAuthorizationServerMiddleware).Namespace,
        "Refresh_Token", "v1");
    Options.RefreshTokenFormat = new TicketDataFormat(dataProtecter);
}
9
Johnny Qian

en plus de johnny-qian réponse, il est préférable d'utiliser cette méthode pour créer DataProtector. johnny-qian réponse, dépend de IIS et échoue sur les scénarios auto-hébergés.

using Microsoft.Owin.Security.DataProtection;
var dataProtector = app.CreateDataProtector(new string[]   {
     typeof(OAuthAuthorizationServerMiddleware).Namespace,
     "Access_Token",
     "v1"
});
1
Mahmoud Moravej

À quoi ressemble votre jeton, est-ce une chaîne de cryptage ou une chaîne formatée, à quoi sert-il?

Je mon code:

public static Action<AuthenticationTokenReceiveContext> receive = new Action<AuthenticationTokenReceiveContext>(c =>
{
        if (!string.IsNullOrEmpty(c.Token))
        {

            c.DeserializeTicket(c.Token);
            //c.OwinContext.Environment["Properties"] = c.Ticket.Properties;
        }
});

Le c.Ticket est toujours nul.

0
Nguyen Tu Pham