簡體   English   中英

Web API 2 OWIN承載令牌認證 - AccessTokenFormat null?

[英]Web API 2 OWIN Bearer token authentication - AccessTokenFormat null?

我有一個現有的ASP.NET MVC 5項目,我正在添加一個Web API 2項目。 我想使用不記名令牌認證,並遵循Hongye Sun的教程“使用Web API示例進行OWIN承載令牌認證” 這個問題

在我的Login方法中,對於Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket); AccessTokenFormat為null。 知道為什么嗎?

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

啟動課程:

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只是添加了一個額外的屬性:

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

MyUserManager將我的自定義用戶身份驗證方法調用到內部服務器:

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 (我從SPA模板中獲取了此信息。僅更改了GrantResourceOwnerCredentials ):

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

AccessTokenFormat是如何設置的? 我的設置是否正確? 我沒有對任何外部服務進行身份驗證,只是一個傳統的內部服務器。 謝謝。

我遇到了同樣的問題 - 這與我在Startup()中的初始化有關。

和你一樣,我將OAuthBearerOptions存儲在一個靜態字段中:

OAuthBearerOptions = new OAuthBearerAuthenticationOptions();

但后來我錯誤地使用了同一個類的新實例

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

顯然,修復是使用靜態字段:

app.UseOAuthBearerAuthentication(OAuthBearerOptions);

實際上,它看起來根本就不像你調用UseOAuthBearerAuthentication()。 我跟隨了Taiseer Joudeh的這一系列優秀帖子

完全啟動.s:

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...]
    }
}

我不確定你是否還在尋找答案 - 但是我在AngularJS應用程序中使用了一些代碼來從我的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);
    });

然后,我可以在任何其他請求的標頭中傳遞accessToken,以獲得身份驗證驗證。

我刪除了示例代碼,因為它與Web API和SPA模板一起使用時會引起混淆。 您最好使用模板代碼來使用OAuth授權服務器來生成令牌。 在您的方案中,您應該使用資源所有者密碼授予來驗證用戶。 請在http://blogs.msdn.com/b/webdev/archive/2013/09/20/understanding-security-features-in-spa-template.aspx上查看我的SPA模板博客,其中包含有關密碼流的詳細信息。

您需要使用OWIN OAuth服務器的/令牌端點來處理密碼登錄,而不是編寫自己的Web API來處理登錄。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM