Angular 5和.NET Core 2的Windows身份验证

3
我的前端运行在localhost:4200上,后端运行在localhost:5000上。 我已经在前端和后端上设置了Windows身份验证,如下所示。 Program.cs
public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
     WebHost.CreateDefaultBuilder(args)
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseStartup<Startup>()
        .Build();
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<IISOptions>(options =>
    {
        options.AutomaticAuthentication = true;
    });

    services.AddAuthentication(IISDefaults.AuthenticationScheme);

    services.AddAuthorization(options => {
            options.AddPolicy("AllUsers", policy => {
                policy.AddAuthenticationSchemes(IISDefaults.AuthenticationScheme);
                policy.RequireRole("S - 1 - 1 - 0");
            });
     });

    services.AddCors(options =>
    {
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials());
    });

   var mvcBuilder = services.AddMvc();
   mvcBuilder.AddJsonOptions(opts => opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver());
  services.AddAutoMapper(typeof(Startup));
  services.AddSingleton<IConfigurationRoot>(_config);
  services.AddRouting();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole();


    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();

    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();
    DefaultFilesOptions options = new DefaultFilesOptions();
    options.DefaultFileNames.Clear();
    options.DefaultFileNames.Add("index.html");
    app.UseDefaultFiles(options);

    app.UseAuthentication();

    app.UseCors("CorsPolicy");


    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });

    // Route all unknown requests to app root
    app.Use(async (context, next) =>
    {
        await next();

        // If there's no available file and the request doesn't contain an extension, we're probably trying to access a page.
        // Rewrite request to use app root
        if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value))
        {
            context.Request.Path = "/index.html"; // Put your Angular root page here 
            context.Response.StatusCode = 200; // Make sure we update the status code, otherwise it returns 404
            await next();
        }
    });

}

在控制器上,

[Authorize]
[Route("/api/service/testWinAuth")]
[EnableCors("CorsPolicy")]
public class TestWinAuth : Controller
{
 ....
}

在这个控制器的方法中,我有以下代码:
[Route("/{id}/{withVoids?}")]
[HttpGet]
[Authorize]
public Object testMethod(Int64? id, String withVoids)
{
    var userId = HttpContext.User.Identity.Name;

}

launchSettings.json

{
  "iisSettings": {
    "windowsAuthentication": true,
    "anonymousAuthentication": false,
    "iisExpress": {
      "applicationUrl": "http://localhost:5000/",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "webapi": {
      "commandName": "Project",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:5001/"
    }
  }
}

在前端方面,我有以下设置:

proxy.conf.json

{
  "/api": {
    "target": "http://localhost:5000",
    "secure": false
  }
}

该HTTP请求设置了选项withCredentials = true

get(url: string, options?: RequestOptionsArgs): Observable<Response> {
  if (!options) {
    const headers = new Headers({ 'Content-Type': 'application/json' });
    options = new RequestOptions({ headers: headers, withCredentials: true });
  }
  // noinspection TypeScriptUnresolvedFunction
  return super.get(url, options)
    .map(r => r)
    .catch((error: any): Observable<Response> =>
      this.errorDisplayAndRedirect(error));
}

访问URL localhost:4200时,它会要求输入用户名和密码,经过身份验证后显示页面。 当我点击发送Get请求的按钮时,它再次要求进行身份验证,但这一次不进行身份验证,我收到了401未经授权的错误。 但是,当我直接使用URL访问后端时,它会要求输入用户名和密码,并按预期进行身份验证。 如何正确地将身份验证信息从前端传递到后端?


可能会有帮助的链接:https://serverfault.com/questions/385025/windows-authentication-kept-asking-for-username-password - Priyesh Kumar
你的UI/API托管在哪里?IIS吗?如果是IIS,那么你需要为它们都启用Windows身份验证。禁用匿名。 - Priyesh Kumar
是的,它托管在IIS上,启用了Windows身份验证,并且对于WebApp和WebApi,禁用了匿名身份验证。 - dosnam
1个回答

2

在阅读了相关文章如何在Angular应用程序和独立Web API中实现Windows身份验证后,我注意到以下代码与上述观点相矛盾:"您不能在*的来源中同时将SupportsCredentials设置为true。"。

services.AddCors(options =>
{
    options.AddPolicy("CorsPolicy",
        builder => builder.AllowAnyOrigin()
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials());
});

也就是说,当您允许凭据时,您同时也允许任何来源。

您是否考虑替换 .AllowAnyOrigin() 为 .WithOrigins("http://localhost:4200") 或类似的内容?

请记住,我没有使用您的代码,但是在提供了特定的来源后,它开始对我起作用。

祝好运。


另外一个对于诊断客户端和服务器之间交互非常有帮助的文章是:https://blogs.technet.microsoft.com/mist/2018/02/14/windows-authentication-http-request-flow-in-iis/...以及像 Fiddler 这样的网络跟踪工具。 - DBallantyne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接