WebApi上的AngularJS和OWIN身份验证

时间:2014-06-27 22:23:38

标签: angularjs authentication asp.net-web-api cors owin

我在WebApi上实现了基于OWIN令牌的身份验证,我也通过调用app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll)

启用了CORS

我可以从angularjs网络客户端访问我的应用程序的各种不安全部分。我使用this http-interceptor,当我尝试访问受保护的资源时,我的登录名为pop。

现在为了登录,我必须使用表格编码的UserName密码和grant_type来呼叫http://mywebapi/token,请参阅下面的标题签名(来自chrome)

Request URL:http://mywebapi/token
Request Headers CAUTION: Provisional headers are shown.
Accept:application/json, text/plain, */*
cache:false
Content-Type:application/x-www-form-urlencoded
Origin:http://127.0.0.1:49408
Referer:http://127.0.0.1:49408/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36
Form Dataview sourceview URL encoded
grant_type:password
UserName:correctuser
Password:Password

当我使用邮递员发送此请求时,它会以预期的accessstoken恢复正常,但是当我尝试使用angular的$ http服务时,它会发出OPTIONS请求(我可以在Dev工具控制台中看到这一点)但对于某些人来说我收到此错误消息的原因

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:49408' is therefore not allowed access.

注意:这仅适用于/ token请求,即form-url-encoded,对于所有其他json请求,标头按预期添加。有人可以帮忙,我的想法已经不多了。

由于

5 个答案:

答案 0 :(得分:17)

我经历了同样的过程并花费(浪费?)与大多数人相同的时间,处理owin + web api。

对我有用的解决方案是移动

app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

在管道中的其他所有内容之前。

以下是一些代码:

<强> OwinStartup

[assembly: OwinStartup(typeof(MyApp.Web.Startup))]
namespace MyApp.Web
{
    using Owin;
    using Microsoft.Owin;

    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
        var config = new System.Web.Http.HttpConfiguration();
        ConfigureAuth(app, config);
        }
    }
}

启动OAuth

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app, System.Web.Http.HttpConfiguration config)
        {
        // app.UseWelcomePage("/");
        // app.UseErrorPage();

        // Must be the first to be set otherwise it won't work.
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

        app.CreatePerOwinContext<ApplicationDatabaseContext>(ApplicationDatabaseContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

        var OAuthOptions = new OAuthAuthorizationServerOptions
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new DaufAuthorizationServerProvider(),
            RefreshTokenProvider = new SimpleAuthorizationServerProvider(),
        };
        app.UseOAuthAuthorizationServer(OAuthOptions);

        app.UseWebApi(WebApiConfig.Register(config, logger));
        }
}

Web Api

public static class WebApiConfig
{
    public static HttpConfiguration Register(System.Web.Http.HttpConfiguration config, ILogger logger)
        {
            // Web API configuration and services
            // Configure Web API to use only bearer token authentication.
            // This will used the HTTP header: "Authorization"      Value: "Bearer 1234123412341234asdfasdfasdfasdf"
            config.SuppressDefaultHostAuthentication();
            config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            return (config);
        }
}

答案 1 :(得分:12)

所以我找到了答案但是让自己感到高兴,因为这个很奇怪!我阅读了this article on code project,它引导我使用我的Owin授权服务器的GrantResourceOwnerCredentials方法来检查这个

context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

(我是一个自定义的Authoris(z)服务器,我将其中一个here删除了

我发现令人震惊的事情是它已经存在了!

所以我决定在那条线上设置一个断点,你知道什么,这条线路失败了,因为(......更令人震惊)“Access-Control-Allow-Origin”已经在标题中!

所以我评论说,这一切都有效!但后来警告,我不知道标题是如何进入的,所以我不知道它是否会在生产中存在,所以我将这行代码交换到检查然后添加它,如果它还没有

var header = context.OwinContext.Response.Headers.SingleOrDefault(h => h.Key == "Access-Control-Allow-Origin");
            if (header.Equals(default(KeyValuePair<string, string[]>)))
            {
                context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
            }

我希望我的爱心能够拯救一些灵魂,使他免受无数个小时的诅咒,无法解决这个问题。干杯!

答案 2 :(得分:7)

对于那些对答案和前一个答案充满好奇的人来说,这确实与排序密切相关。无论何时添加Owin中间件,都必须注意:注册顺序是必不可少的。

app.useCors(Microsoft.Owin.Cors.CorsOptions.AllowAll)

将此作为auth文件中的第一件事,基本上是在到达OAuthServer和Web Api之前注册Cors处理程序。

在OAuth执行相反操作后移动它,因此需要在GrantResourceOwnerCredentials中添加Access-Control-Allow-Origin标头。

要回答另一个问题,标头已经存在的原因是,如果您从浏览器发送了CORS请求并且指定了CorsOptions.AllowAll,那么它会在您到达/ token端点时为您添加一个它已经添加了一个OAuth服务器。 (只是意味着在http请求中找到了一个,并允许所有来源)。

您可以相应地验证行为,

在Fiddler中,向您的令牌端点发送一个新请求,其中包含一个包含任意值的Origin头。在GrantResourceOwnerCredentials中的OAuth服务器上放置一个断点,然后检查context.Response.Headers,它现在将包含您传入的来源。(请记住,浏览器必须检查它,fiddler会整天开心)

如果你告诉CORS不要使用CorsOptions.AllowAll并将AllowAnyOrigin设置为false,你会发现从Fiddler发送的Origin不再被添加到响应头。

浏览器依次拒绝CORS请求,因为没有返回原点 - 在Access-Control-Allow-Origin标题中找不到Origin。“

现在重要的位置:

如果你设置CorsOptions.AllowAll它完全按照它所说的做,允许对Owin管道中CORS注册后发生的任何中间件上的任何方法的CORS请求,所以确保这是你打算做的。 IE:如果您首先注册CORS然后注册OAuth和Web API,那么如果您没有明确添加代码\属性来阻止它,那么您可以通过CORS访问所有Web API方法。

如果要限制方法然后实现ICorsPolicyProvider,http://katanaproject.codeplex.com/(Microsoft.Owin.Cors)

中的某些部分
      public class MyCorsPolicyProvider : ICorsPolicyProvider
        {
            public Task<CorsPolicy> GetCorsPolicyAsync(IOwinRequest request)
            {
                // Grant Nothing.
                var policy = new CorsPolicy
                {
                    AllowAnyHeader = false,
                    AllowAnyMethod = false,
                    AllowAnyOrigin = false,
                    SupportsCredentials = false
                };

                // Now we can get a bit clever: (Awesome, they requested the token endpoint. Setup OAuth options for that.
                if (OAuthOptions.TokenEndpointPath.HasValue && OAuthOptions.TokenEndpointPath == request.Path)
                {
                    // Hypothetical scenario, tokens can only be obtained using CORS when the Origin is http://localhost
                    policy.AllowAnyHeader = true;
                    policy.AllowAnyMethod = true;
                    policy.AllowAnyOrigin = false;
                    policy.SupportsCredentials = true;
                    policy.Origins.Add("http://localhost");

                return Task.FromResult(policy);
                }
                // No token?, must already have one.... so this must be a WebApi request then.
                // From here we could check where the request is going, do some other fun stuff etc... etc...
                // Alternatively, do nothing, set config.EnableCors() in WebApi, then apply the EnableCors() attribute on your methods to allow it through.
return null;            }
        }

返回null;告诉Owin继续使用下一个中间件并允许请求通过但没有策略因此NO CORS!允许您在WebAPI中设置适当的CORS属性

现在非常重要的一点,如果它不存在,请不要将Access-Control-Allow-Origins标头添加到您的响应中,除非您真正想要的是根据您的中间件注册顺序它将打开所有CORS请求的大门,除非你在其他地方明确地阻止它们或删除标题,当你尝试将CORS与WebApi一起使用并且想要限制它时,基本上会引起很多问题。

要在其他地方阻止它们,您可以为WebApi添加CorsPolicyProvider(System.Web.Http),然后在Owin中设置一个Context变量,一旦请求到达WebApi,您就可以读取该变量。

    public class WebApiCorsPolicyProvider : System.Web.Http.Cors.ICorsPolicyProvider
    {
        public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var policy = new CorsPolicy
            {
                AllowAnyHeader = false,
                AllowAnyMethod = false,
                AllowAnyOrigin = false,
                SupportsCredentials = false
            };
// The benefit of being at this point in the pipeline is we have been authenticated\authorized so can check all our claims for CORS purposes too if needed and set errors etc...

            // In an Owin pipeline?
            var owinContext = request.GetOwinContext();

            if (owinContext != null)
            {
               // We have an owin pipeline, we can get owin parameters and other things here.
            }
            else
            {
                // Write your code here to determine the right CORS options. Non Owin pipeline variant.   
            }

            return Task.FromResult(policy);
        }
    }

最后,向下传播到WebApi CORS策略提供者的另一个好处是,此时将进行授权,以便您可以在CORS策略提供者的该阶段应用其他Origin过滤器。

答案 3 :(得分:2)

在我看来,虽然我没有进一步调查,但它与你的陈述的排序有关。我遇到了同样的问题并尝试了所有组合,并最终为我工作。

        public void Configuration(IAppBuilder app)
    {
        HttpConfiguration config = new HttpConfiguration();

        ConfigureOAuth(app);
        WebApiConfig.Register(config);
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

        app.UseWebApi(config);
    }

我关注Token Based Authentication using ASP.NET Web API 2, Owin, and Identity

答案 4 :(得分:1)

这是Obi Onuorah的回复代码的另一个版本

        string corsHeader = "Access-Control-Allow-Origin";
        if (!context.Response.Headers.ContainsKey(corsHeader))
        {
            context.Response.Headers.Add(corsHeader, new[] { "*" }); 
        }