Get IPrincipal from OAuth Bearer Token in OWIN

前端 未结 4 1490
说谎
说谎 2020-11-29 22:04

I have successfully added OAuth to my WebAPI 2 project using OWIN. I receive tokens and can use them in the HTTP Header to access resources.

Now I want to use those

相关标签:
4条回答
  • 2020-11-29 22:16

    By default, OWIN use ASP.NET machine key data protection to protect the OAuth access token when hosted on IIS. You can use MachineKey class in System.Web.dll to unprotect the tokens.

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

    Then, construct a TicketDataFormat to get the AuthenticationTicket object where you can get the ClaimsIdentity and AuthenticationProperties.

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

    To unprotect other OAuth tokens, you just need to change the _purpose content. For detailed information, see OAuthAuthorizationServerMiddleware class here: 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);
    }
    
    0 讨论(0)
  • 2020-11-29 22:17

    in addition to johnny-qian answer, using this method is better to create DataProtector. johnny-qian answer, depends on IIS and fails on self-hosted scenarios.

    using Microsoft.Owin.Security.DataProtection;
    var dataProtector = app.CreateDataProtector(new string[]   {
         typeof(OAuthAuthorizationServerMiddleware).Namespace,
         "Access_Token",
         "v1"
    });
    
    0 讨论(0)
  • 2020-11-29 22:25

    I found a part of the solution in this blog post: http://leastprivilege.com/2013/10/31/retrieving-bearer-tokens-from-alternative-locations-in-katanaowin/

    So I created my own Provider as follows:

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

    Then I needed to add it to my App in Startup.Auth.cs like this:

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

    With a custom AuthenticationTokenProvider, I can retrieve all other values from the token early in the 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;
    });
    

    And now, for example in my WebSocket Hander, I can retrieve ClientId and others like this:

    IOwinContext owinContext = context.GetOwinContext();
    if (owinContext.Environment.ContainsKey("Properties"))
    {
        AuthenticationProperties properties = owinContext.Environment["Properties"] as AuthenticationProperties;
        string clientId = properties.Dictionary["clientId"];
    ...
     }
    
    0 讨论(0)
  • 2020-11-29 22:33

    What is your token like, is it an encrypt string or a formatted string, what is it format?

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

    The c.Ticket is always null.

    0 讨论(0)
提交回复
热议问题