首页 > 解决方案 > 如何将 reactjs web 应用程序修复为 .net webapi 授权错误

问题描述

我有一个应用程序,其中 Web UI (reactjs) 和 Web API (.net) 部署在两个不同的服务器上。但是,当我将我的 API 身份验证设置为 Windows 时,它不断给我错误: Failed to load resource: the server responded with a status of 401 (Unauthorized)

当我有以下设置时,我可以浏览已部署的应用程序链接:
UI Site: Windows Authentication
API Site: Anonymous Authentication.

但这并不能帮助我获得登录的用户 ID。以登录用户的身份返回 iis/app-pool 名称。

因此,我将设置更改为以下内容:
UI Site: Windows Authentication
API Site: Windows Authentication and ASP.NET Impersonation.

现在我在 UI 中遇到第一个 API 时出现授权错误。需要注意的是,如果我直接访问 API 链接,它会返回结果并将我的用户 ID 作为记录的用户 ID。

我尝试了互联网上建议的各种解决方案,包括以下步骤 1 到 4: 如何将 Windows 身份验证凭据从客户端传递到 Web API 服务,但尚未成功。

有没有人遇到过这样的问题并找到了解决办法?

编辑: 我按照 Alexandre Rodrigues 在下面的回复中建议的步骤进行了操作。我按照链接中的说明启用了 CORS。

第一个问题是:The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute

所以我继续并在以下位置添加了网站路径:

[EnableCors(origins: "http:myexample.com", headers: "*", methods: "*", SupportsCredentials = true)] 

它只是没有帮助,然后我在 web.config 中添加了以下几行:

<httpProtocol>
   <customHeaders>
      <add name="Access-Control-Allow-Methods" value="POST,GET" />
      <add name="Access-Control-Allow-Origin" value="http://myexample.com" /> 
      <add name="Access-Control-Allow-Credentials" value="true" />
      <add name="Access-Control-Allow-Headers" value="cache-control,content-type,man,messagetype,soapaction" />
   </customHeaders>
</httpProtocol>

我得到的下一个错误是:

The value of the 'Access-Control-Allow-Credentials' header in the response is 'true, true' which must be 'true'.

The value of the 'Access-Control-Allow-Origin' header in the response is 'http://myexample.com, http://myexample(index).com' which must be 'http://myexample.com'

因此,作为最后的手段,我在我的 WebAPI 的下面一行评论并重新部署了应用程序。

[EnableCors(origins: "http:myexample.com", headers: "*", methods: "*", SupportsCredentials = true)]

那行得通!这导致应用程序显示两个控制器的结果:一个我设置了授权,一个没有授权。

这些错误仅由我添加了 [Authorize] 的控制器引发,因为另一个大部分时间都在返回结果。

所以我的问题是,这是常规身份验证和授权应该如何工作还是我评论了 Authorization 的一个非常重要的部分?更新:所以这只会让 GET 请求工作而不是 POST。 请求标头: Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: cache-control,content-type,man,messagetype,soapaction Access-Control-Allow-Methods: POST,GET Access-Control-Allow-Origin: http://myexample.com **Response Header** Provisional headers are shown Access-Control-Request-Headers: content-type Access-Control-Request-Method: POST Origin: http://myexample.com Referer: http://myexample.com/form/1001 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36

标签: asp.net-mvcreactjsiisauthorizationwindows-authentication

解决方案


先决条件

要从 Reactjs 或任何 Ajax 方法访问任何 Web API,Web API 必须启用CORS

网络配置代码片段

<system.web>  
    <authentication mode="Windows" ></authentication>  
</system.web>  

在控制器或任何操作方法上使用Authorize 属性以确保安全

例子

[EnableCors(origins: "*", headers: "*", methods: "*", SupportsCredentials = true)]  
    public partial class WebAPIController : ApiController  
    {  
   
        [HttpGet]  
        [Authorize]  
        [Route("api/AuthenticateUser")]  
   
        public HttpResponseMessage AuthenticateUser()  
        {  
            if (User != null)  
            {  
                 return Request.CreateResponse(HttpStatusCode.OK, new  
                {  
                    status = (int)HttpStatusCode.OK,  
                    isAuthenticated = true,  
                    isLibraryAdmin = User.IsInRole(@"domain\AdminGroup"),  
                    username = User.Identity.Name.Substring(User.Identity.Name.LastIndexOf(@"\") + 1)  
                });  
            }  
            else  
            {  
//This code never execute as we have used Authorize attribute on action method  
                return Request.CreateResponse(HttpStatusCode.OK, new  
                {  
                    status = (int)HttpStatusCode.BadRequest,  
                    isAuthenticated = false,  
                    isLibraryAdmin = false,  
                    username = ""  
                });  
   
            }  
         }  
    }

[Authorize]属性确保仅在用户输入有效凭据时才执行操作,否则将显示 401 Unauthorized access。

如果您收到“此请求的授权已被拒绝”,请查看此帖子

因此,基于上述堆栈溢出问题提供的解决方案,需要在位于项目根目录“.vs\config”的“applicationhost.config”文件中对 Windows 身份验证()进行更多配置,此文件夹是隐藏的,您必须启用显示所有隐藏文件和文件夹选项。

<windowsAuthentication enabled="true">
   <providers>
       <add value="Negotiate" />
       <add value="NTLM" />
       </providers>
</windowsAuthentication>

CORS 从服务器端启用。现在在请求 API 时,从前端传递标志 withCredentials: true 。

对于 jQuery Ajax,您必须按如下方式传递请求。

$.ajax({url:apiURL ,xhrFields: {   withCredentials: true }, success:successHandler }); 

对于 Reactjs,您必须按如下方式传递请求。

private options = new RequestOptions({ withCredentials: true });  
this.http.get(this.baseUrl, this.options) 

阿贾克斯代码段

var apiURL="http://localhost:51647/api/AuthenticateUser";  
$.ajax({
    url:apiURL ,
    xhrFields: { withCredentials: true }, 
    success: function(result){  
    console.log(JSON.stringify(result));  
}});    

已编辑

让我们启用 CORS

预检请求(选项)

<system.web>
    <authentication mode="Windows" />
    <authorization>
        <allow verbs="OPTIONS" users="*"/>
        <deny users="?" />
    </authorization>
</system.web>

全局.asax.cs

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    if (Context.Request.HttpMethod == "OPTIONS")
    {
        if (Context.Request.Headers["Origin"] != null)
            Context.Response.AddHeader("Access-Control-Allow-Origin", Context.Request.Headers["Origin"]);

        Context.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, MaxDataServiceVersion");
        Context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        Context.Response.AddHeader("Access-Control-Allow-Credentials", "true");

        Response.End();
    }
}

启用 CORS

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // all requests are enabled in this example. SupportsCredentials must be here to allow authenticated requests          
        var corsAttr = new EnableCorsAttribute("*", "*", "*") { SupportsCredentials = true };
        config.EnableCors(corsAttr);
    }
}

protected void Application_Start()
{
    GlobalConfiguration.Configure(WebApiConfig.Register);
}

例子


推荐阅读