首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IdentityServer4资源所有者密码和Win auth:未经授权

IdentityServer4资源所有者密码和Win auth:未经授权
EN

Stack Overflow用户
提问于 2019-07-30 13:52:29
回答 1查看 897关注 0票数 0

在过去的几天里,我一直在阅读IdentityServer4文档,并使用Resource密码将示例服务器+示例客户机组装在一起。现在,我想并行地添加Windows身份验证(将通过Active Directory完成),这样客户端应用程序(不是web应用程序,而是桌面应用程序)可以提示用户提供凭据,或者通过Active使用Windows身份验证登录。

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

  1. 用户打开应用程序
  2. 应用程序使用单点登录将请求发送到web api以请求令牌和刷新令牌。
  3. web api使用windows身份验证来验证用户的身份并返回令牌。

我试着遵循这个answer,但它不工作(它返回未经授权)。

web : Startup.cs

代码语言:javascript
复制
    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 };
        }
    }
}
}

web : Program.cs

代码语言:javascript
复制
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 UserController.cs

代码语言:javascript
复制
[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 };
    }
}

客户代码:

代码语言:javascript
复制
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;
         }
     }

它会返回未经授权的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-09-03 11:15:35

我找到了一个解决方案:我需要用TestUser配置一个SubjectId = MYDOMAIN\myusername,然后它就开始工作了。

这一错误变得过于混乱。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57273372

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档