IdentityServer4资源所有者密码和Win身份验证:未授权 [英] IdentityServer4 Resource owner password and Win auth: unauthorized

查看:322
本文介绍了IdentityServer4资源所有者密码和Win身份验证:未授权的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近几天,我一直在阅读IdentityServer4文档,并使用资源所有者密码将示例服务器+示例客户端放在一起.现在,我想并行添加Windows身份验证(将通过Active Directory完成),因此客户端应用程序(不是Web应用程序,而是桌面应用程序)可以提示用户输入凭据,也可以使用Windows身份验证通过Active Directory登录.

in the last few days I've been reading IdentityServer4 docs and putting together my sample server + sample client using Resource owner password. Now I'd like to add Windows authentication (will be done via Active Directory) in parallel, so the client app (not a web app but a desktop app) could either prompt the user for credentials or login using Windows authentication via Active Directory.

有关Windows身份验证的文档介绍了如何配置IIS或HTTP.Sys,但是我想要做的是:

The documentation about Windows Authentication explains how to configure IIS or HTTP.Sys, but what I want is to:

  1. 用户打开应用程序
  2. 该应用使用单点登录将请求发布到Web api,以请求令牌和刷新令牌
  3. Web api使用Windows身份验证来验证用户身份并返回令牌

我尝试遵循此答案,但是它不起作用(返回未经授权的内容).

I've tried to follow this answer, but it doesn't work (It returns unauthorized).

网络api:Startup.cs

web api: Startup.cs

    public class Startup
    {

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvcCore()
                .AddAuthorization()
                .AddJsonFormatters();


            services.AddAuthentication("Bearer")    
            .AddJwtBearer(options =>
            {
                // base-address of your identityserver
                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;
                // name of the API resource
                options.Audience = "api/user";
            });

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            services.AddIdentityServer(options => { options.PublicOrigin = "http://localhost:5000"; options.MutualTls.Enabled = false; })                
                .AddExtensionGrantValidator<WinAuthGrantValidator>()
                .AddDeveloperSigningCredential()
                .AddTestUsers(Config.GetUsers())
                .AddInMemoryApiResources(Config.GetApiResources())
                .AddInMemoryClients(Config.GetClients())
                .AddInMemoryIdentityResources(Config.GetIdentityResources());

        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env,
            ILogger<Startup> logger, IServer server)
        {
            app.Use(async (context, next) =>
            {
                context.Features.Get<IHttpMaxRequestBodySizeFeature>()
                    .MaxRequestBodySize = 10 * 1024;

                var serverAddressesFeature =
                    app.ServerFeatures.Get<IServerAddressesFeature>();
                var addresses = string.Join(", ", serverAddressesFeature?.Addresses);

                logger.LogInformation($"Addresses: {addresses}");

                await next.Invoke();

            });
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");

                app.UseHsts();
            }

            // Enable HTTPS Redirection Middleware when hosting the app securely.
            //app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
            app.UseMvc();
            app.UseIdentityServer();
            app.UseAuthentication();
        }
    }

    internal static class Config
    {
        public static List<TestUser> GetUsers()
        {
            return new List<TestUser>
            {
                new TestUser
                {
                    SubjectId = "1",
                    Username = "alice",
                    Password = "password"
                },
                new TestUser
                {
                    SubjectId = "2",
                    Username = "bob",
                    Password = "password"
                }
            };
        }

        public static IEnumerable<Client> GetClients()
        {
            return new List<Client>
            {
                // other clients omitted...

                // resource owner password grant client
                new Client
                {
                    ClientId = "ro.client",
                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,

                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    },
                   // AllowedScopes = { "api1" }
                   AllowedScopes = { "api/user" }
                },
            new Client
            {
                ClientId = "winauth",
                AllowedGrantTypes =  new List<string>{ "windows_auth" },

                ClientSecrets =
                {
                    new Secret("secret".Sha256())
                },
               // AllowedScopes = { "api1" }
               AllowedScopes = { "api/user" }
             }
            };
        }

        internal static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource { Name = "api1",Scopes = new List<Scope> { new Scope {  Name = "api1",
                    DisplayName = "Full access to API 2"}  }, Enabled = true,  ApiSecrets = new List<Secret>
                    {
                        new Secret("secret".Sha256())
                    }
                },
                new ApiResource { Name = "api/user",Scopes = new List<Scope> { new Scope {  Name = "api/user",
                    DisplayName = "Full access to API 2"}  }, Enabled = true,  ApiSecrets = new List<Secret>
                    {
                        new Secret("secret".Sha256())
                    }
                }};
        }


        public static List<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile()
            };
        }
    }



public class WinAuthGrantValidator : IExtensionGrantValidator
    {
    private readonly HttpContext httpContext;

    public string GrantType => "windows_auth";

    public WinAuthGrantValidator(IHttpContextAccessor httpContextAccessor)
    {
        httpContext = httpContextAccessor.HttpContext;
    }

    public async Task ValidateAsync(ExtensionGrantValidationContext context)
    {
        // see if windows auth has already been requested and succeeded
        var result = await httpContext.AuthenticateAsync("Windows");
        if (result?.Principal is WindowsPrincipal wp)
        {
            context.Result = new GrantValidationResult(wp.Identity.Name, GrantType, wp.Claims);
        }
        else
        {
            // trigger windows auth
            await httpContext.ChallengeAsync("Windows");
            context.Result = new GrantValidationResult { IsError = false, Error = null, Subject = null };
        }
    }
}
}

网络API:Program.cs

web API: Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        var isService = !(Debugger.IsAttached || args.Contains("--console"));

        if (isService)
        {
            var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
            var pathToContentRoot = Path.GetDirectoryName(pathToExe);
            Directory.SetCurrentDirectory(pathToContentRoot);
        }

        var builder = CreateWebHostBuilder(
            args.Where(arg => arg != "--console").ToArray());

        var host = builder.Build();

        if (isService)
        {
            // To run the app without the CustomWebHostService change the
            // next line to host.RunAsService();
            host.RunAsCustomService();
        }
        else
        {
            host.Run();
        }
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureLogging((hostingContext, logging) =>
            {
                logging.AddEventLog();
            })
            .ConfigureAppConfiguration((context, config) =>
            {
                // Configure the app here.
            })
            .UseStartup<Startup>()
            .UseHttpSys(options =>
            {
                options.AllowSynchronousIO = true;
                options.Authentication.Schemes = Microsoft.AspNetCore.Server.HttpSys.AuthenticationSchemes.Kerberos | Microsoft.AspNetCore.Server.HttpSys.AuthenticationSchemes.NTLM;
                options.Authentication.AllowAnonymous = true;
                options.MaxConnections = null;
                options.MaxRequestBodySize = 30000000;
                options.UrlPrefixes.Add("http://localhost:5000");
            });
}

web API UserController.cs

web API UserController.cs

[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = "Bearer")]
[ApiController]
public class UserController : ControllerBase
{
    // GET api/user
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new string[] { User.Identity.Name, User.Identity.AuthenticationType };
    }
}

客户代码:

using (var client = new HttpClient())
{
    disco = await client.GetDiscoveryDocumentAsync(new   DiscoveryDocumentRequest
    {
        Address = baseUrl,
        Policy = { RequireHttps = false }
    });
    if (disco.IsError)
    {
        Console.WriteLine(disco.Error);
        Console.ReadLine();
        return;
     }
     var httpHandler = new HttpClientHandler
     {
         UseDefaultCredentials = true,
     };

     using (var client = new HttpClient())
     {
         // request token
         TokenResponse tokenResponse = await client.RequestTokenAsync(new TokenRequest
         {
             GrantType = "windows_auth",
             Address = disco.TokenEndpoint,
             ClientId = "winauth",
             ClientSecret = "secret"
         });

         if (tokenResponse.IsError)
         {
             Console.WriteLine(tokenResponse.Error);
             Console.ReadLine();
            return;
         }
     }

它返回未经授权的内容.

It returns unauthorized.

推荐答案

我找到了一个解决方案:我需要使用SubjectId = MYDOMAIN\myusername配置一个TestUser,然后它才能起作用.

I found a solution to this: I need to configure a TestUser with SubjectId = MYDOMAIN\myusername then it worked.

得到的错误过于混乱.

这篇关于IdentityServer4资源所有者密码和Win身份验证:未授权的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆