Angular4 ASP.NET Core 1.2 Windows Authentication CORS for PUT 和 POST 给出 401

Posted

技术标签:

【中文标题】Angular4 ASP.NET Core 1.2 Windows Authentication CORS for PUT 和 POST 给出 401【英文标题】:Angular4 ASP.NET Core 1.2 Windows Authentication CORS for PUT and POST Gives 401 【发布时间】:2017-12-19 20:52:54 【问题描述】:

我的 IDE 是 Visual Studio 2017。我有一个 Angular4 客户端与 Core 中的 WebAPI 后端通信,并且 CORS 按配置工作,除了 PUT 和 POST 方法。 GET 方法与 PUT 和 POST 方法在 Chrome 中使用相同的预检 OPTIONS 方法,但 GET 工作正常。

Visual Studio 中的 IIS Express 服务器似乎没有将请求转发到 Kestrel 服务器。这两种方法都可以在 Postman 中使用,但在 Angular4 进行调用时不起作用。代码如下:

Angular4 发布

post(api: string, object: any): Observable<any> 
        let body = JSON.stringify(object);

        let options = new RequestOptions(
            headers: this.headers,
            withCredentials: true
            );

        return this.http.post(this.server + api, body, options)
            .map((res: Response) => res.json())
            .catch((error: any) => Observable.throw(error.json().error) || 'Post server error');
    

Startup.cs 配置

services.Configure<IISOptions>(options => 
     options.ForwardWindowsAuthentication = true);

services.AddCors(options => 
            options.AddPolicy("AllowAll", builder => 
                builder.WithOrigins("http://localhost:XXXX")
                .WithMethods("GE‌​T", "POST", "PUT", "DELETE", "OPTIONS")
                .WithHeaders("Origin", "X-Requested-With", "Content-Type", "Accept", "Authorization")
                .AllowCredentials();
            );
        );

Startup.cs 配置服务

app.UseCors("AllowAll");

项目中的 IIS ApplicationHost.Config

<anonymousAuthentication enabled="false" userName="" />
    <basicAuthentication enabled="false" />
    <clientCertificateMappingAuthentication enabled="false" />
    <digestAuthentication enabled="false" />
    <iisClientCertificateMappingAuthentication enabled="false"></iisClientCertificateMappingAuthentication>
    <windowsAuthentication enabled="true" >
      <providers>
        <add value="Negotiate" />
      </providers>
    </windowsAuthentication>

<customHeaders>
    <clear />
    <add name="X-Powered-By" value="ASP.NET" />
    <add name="Access-Control-Allow-Origin" value="http://localhost:5000"/>
    <add name="Access-Control-Allow-Headers" value="Accept, Origin, Content-
        Type"/>
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, 
        OPTIONS"/>
    <add name="Access-Control-Allow-Credentials" value="true"/>
</customHeaders>

GET 响应

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: **Kestrel**
X-SourceFiles: =?UTF-8?B?QzpcZGV2cHJvamVjdHNcVFJXRC5IeWRyb21hcnRBZG1pblxKVF9BZGRUYWdNYW5hZ2VtZW50XFRSV0QuSHlkcm9NYXJ0LkFwcFxhcGlcdGFncw==?=
Persistent-Auth: true
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: http://localhost:5000
Access-Control-Allow-Headers: Accept, Origin, Content-Type
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Date: Fri, 14 Jul 2017 17:03:43 GMT

对 POST 的响应

HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/10.0
X-SourceFiles: =?UTF-8?B?QzpcZGV2cHJvamVjdHNcVFJXRC5IeWRyb21hcnRBZG1pblxKVF9BZGRUYWdNYW5hZ2VtZW50XFRSV0QuSHlkcm9NYXJ0LkFwcFxhcGlcdGFncw==?=
WWW-Authenticate: Negotiate
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: http://localhost:5000
Access-Control-Allow-Headers: Accept, Origin, Content-Type
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Credentials: true
Date: Fri, 14 Jul 2017 17:05:11 GMT
Content-Length: 6095

所以最大的问题是,我错过了什么?

【问题讨论】:

【参考方案1】:

知道了。好的,所以基本上,发生的事情是预检 OPTIONS 请求没有授权,所以它是默认和设计的,因为我禁用了匿名身份验证并启用了 Windows 身份验证,所以它失败了。我必须允许客户端和 web api 都进行匿名身份验证,以便 OPTIONS 请求可以毫发无损地通过。然而,这留下了一个我必须解决的巨大安全漏洞。由于我已经打开了 OPTIONS 请求的大门,因此我不得不以某种方式关闭 POST、PUT 和 DELETE 请求的大门。我通过创建仅允许经过身份验证的用户的授权策略来做到这一点。我的最终代码如下:

Angular 4 帖子

注意选项中 withCredentials 的使用。

post(api: string, object: any): Observable<any> 
    let body = JSON.stringify(object);

    let options = new RequestOptions(
        headers: this.headers,
        withCredentials: true
        );

    return this.http.post(this.server + api, body, options)
        .map((res: Response) => res.json())
        .catch((error: any) => Observable.throw(error.json().error) || 'Post server error');

Startup.cs

添加了 CORS,添加了身份验证策略,使用了 CORS。

(在配置服务下)

services.AddCors(options =>
        
            options.AddPolicy("AllowSpecificOrigin",
                builder => builder.WithOrigins("http://localhost:5000")
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());
        );

services.AddAuthorization(options =>
        
            options.AddPolicy("AllUsers", policy => policy.RequireAuthenticatedUser());
        );

(在配置下)

app.UseCors("AllowSpecificOrigin");

控制器

添加了引用在启动中创建的策略的授权。

[Authorize(Policy = "AllUsers")]
    [Route("api/[controller]")]    
    public class TagsController : ITagsController

IISExpress 的applicationhost.config

<authentication>
        <anonymousAuthentication enabled="false" userName="" />
        <basicAuthentication enabled="false" />
        <clientCertificateMappingAuthentication enabled="false" />
        <digestAuthentication enabled="false" />
        <iisClientCertificateMappingAuthentication enabled="false"></iisClientCertificateMappingAuthentication>
        <windowsAuthentication enabled="true">
          <providers>
            <add value="Negotiate" />
            <add value="NTLM" />
          </providers>
        </windowsAuthentication>
      </authentication>

我完全删除了自定义标题。

此解决方案允许所有 4 个动词按预期工作,并且我能够使用 httpContext.User 对象中的识别信息将信息记录到数据库中。

一旦我将它部署到 IIS,我希望必须将 forwardWindowsAuthToken 添加到 web.config:

<aspNetCore processPath=".\TRWD.HydroMart.App.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="true" />

这到 ConfigureServices 中的启动:

services.Configure<IISOptions>(options => 
        options.ForwardWindowsAuthentication = true;
    );

【讨论】:

还发现您必须禁用 API 应用程序的 WebDavModule,以便 PUT 和 DELETE 请求可以通过。通过在应用程序的 web.config 上的 标记内添加 来做到这一点。 这个答案几个月后,微软给出了官方解决方案,blogs.iis.net/iisteam/introducing-iis-cors-1-0配置 IIS CORS 模块,所有这些黑客都变得不必要了。【参考方案2】:

要允许匿名预检选项,您可以将以下内容添加到您的 web.config

<security>
   <authorization>
       <remove users="*" roles="" verbs="" />
       <add accessType="Allow" users="" roles="mydomain/mygroup" />
       <add accessType="Allow" users="?" verbs="OPTIONS" />
   </authorization>
</security>

注意:使用组来限制经过身份验证的用户的访问,并将匿名用户的访问限制为 OPTIONS 动词。

如果您还没有添加 cors 包 Microsoft.AspNetCore.Cors

并配置它。

可以找到配置 CORS 的好指南 here:

【讨论】:

【参考方案3】:

我用非常简单的方法让它工作。我使用 dotNet Core 2.0

In configureServices method of startup

services.AddCors(options =>
        
            options.AddPolicy("app-cors-policy",
                builder =>
                
                    builder
                        .AllowAnyOrigin()
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowCredentials()
                    ;
                );

        );


In configure method of startup

app
   .UseCors("app-cors-policy") //Must precede UseMvc
   .UseMvc();

然后,同时启用匿名身份验证和 Windows 身份验证。 这允许始终匿名的 OPTIONS 请求(预检)通过。所有 xhr 请求都必须带有凭据,否则将失败。

【讨论】:

【参考方案4】:

这对我有用...

首先,在Startup.cs中为ConfigureServices()添加一个CORS策略

services.AddCors(o => o.AddPolicy("CORSPolicy", builder =>
        
            builder.AllowAnyOrigin()
                   .AllowAnyMethod()
                   .AllowAnyHeader()
                   .AllowCredentials();
        ));

并在Configure() 方法中使用

app.UseCors("CORSPolicy");

接下来,将Authorize 属性添加到您的控制器或全局添加它们。我去了全球。为此,请在 ConfigureServices() 方法中的上述 services.AddCors() 方法之后添加以下内容(您也可以在该谓词中包含其他内容)

            services.AddMvc(options =>
        
            var policy = new AuthorizationPolicyBuilder()
                             .RequireAuthenticatedUser()
                             .Build();
            options.Filters.Add(new AuthorizeFilter(policy));
        ); 

然后,我添加了这个小块(这就是让一切对我来说“正常工作”的原因)。基本上,它允许预检请求通过 IIS 而无需进行身份验证。

services.AddAuthentication(IISDefaults.AuthenticationScheme);

我认为您也必须将以下内容添加到您的 usings 中

using Microsoft.AspNetCore.Server.IISIntegration;

您还应该告诉应用使用身份验证。在app.UseCors("CORSPolicy") 下方的Configure() 方法中执行此操作

app.UseAuthentication();

最后,确保在 applicationhost.config 文件中将 anonymousAuthenticationwindowsAuthentication 设置为 true。如果您不知道该文件是什么,它会配置应用程序的 IIS 设置。您可以在 config 文件夹内项目根目录的 hidden .vs 文件夹中找到它。

<authentication>
    <anonymousAuthentication enabled="true" userName="" />
    <basicAuthentication enabled="false" />
    <clientCertificateMappingAuthentication enabled="false" />
    <digestAuthentication enabled="false" />
    <iisClientCertificateMappingAuthentication enabled="false"></iisClientCertificateMappingAuthentication>
    <windowsAuthentication enabled="true">
      <providers>
        <add value="Negotiate" />
        <add value="NTLM" />
      </providers>
    </windowsAuthentication>
  </authentication>

我不知道是否每个人都这样,但我的applicationhost.config 文件中有两个 &lt;authentication&gt;&lt;/authentication&gt; 部分。为了安全起见,我将两者都更改了,并且没有尝试更改其中一个而不是另一个。


**

TLDR;

**

步骤 1)

public void ConfigureServices(IServiceCollection services)
    
        services.AddCors(o => o.AddPolicy("CORSPolicy", builder =>
        
            builder.AllowAnyOrigin()
                   .AllowAnyMethod()
                   .AllowAnyHeader()
                   .AllowCredentials();
        ));

        services.AddAuthentication(IISDefaults.AuthenticationScheme);

        services.AddMvc(options =>
        
            var policy = new AuthorizationPolicyBuilder()
                             .RequireAuthenticatedUser()
                             .Build();
            options.Filters.Add(new AuthorizeFilter(policy));
        ); 
    

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    
        if (env.IsDevelopment())
        
            app.UseDeveloperExceptionPage();
        

        app.UseCors("CORSPolicy");

        app.UseAuthentication();

        app.UseMvc();
    

步骤 2) 在applicationhost.config 您可能需要在文件中的两个位置执行此操作

<authentication>
      <anonymousAuthentication enabled="true" />
      <windowsAuthentication enabled="true" />
    </authentication>

【讨论】:

使用 .Net Core 2.1,Intellisense 不显示 services.AddAuthenticationapp.UseAuthentication。除了using Microsoft.AspNetCore.Server.IISIntegration 之外,我还必须添加到我的using 语句列表中吗? 2018 年人们应该使用 IIS CORS 模块,blogs.iis.net/iisteam/introducing-iis-cors-1-0 不是这样的黑客。【参考方案5】:

现在是这样的:https://www.iis.net/downloads/microsoft/iis-cors-module

“Microsoft IIS CORS 模块是一个使网站能够支持 CORS(跨域资源共享)协议的扩展。”

呜呜呜

【讨论】:

以上是关于Angular4 ASP.NET Core 1.2 Windows Authentication CORS for PUT 和 POST 给出 401的主要内容,如果未能解决你的问题,请参考以下文章

使用angular4和asp.net core 2 web api做个练习项目

使用angular4和asp.net core 2 web api做个练习项目

使用 Google Auth、Angular 4、ASP.Net Core 2 进行身份验证时出现 405

我无法在 asp.net core spas 中添加带有角度 cli 的新组件

ASP.NET Core 2.1 API JWT 令牌 Session.id 在每次请求时都会更改

如何使用 ASP.Net Core Identity 从登录用户中检索 Google 个人资料图片?