首页 > 解决方案 > Web api 未重定向到身份服务器登录页面

问题描述

我正在尝试使用身份服务器和 Web Api 实现 SSO

到目前为止,我已经创建了一个身份服务器项目和一个 Web Api 项目,并根据我正在学习的Pluralsight 课程对其进行了配置。自从创建本课程以来,似乎发生了一些变化,所以我必须做的一些事情与教程不匹配(这可能是我的痛点的原因,但我认为不是)。

我期望发生的是我点击了一个需要授权的控制器,如果需要,我将被重定向到身份服务器登录页面。目前我得到一个 401。我在这里查看了隐式流程的 github 示例,看来我在做正确的事情。

有人可以帮我找到我缺少的东西吗?

身份服务器

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddIdentityServer()
                .AddSigningCredential(new X509Certificate2(@"cert.pfx", "password"))
                .AddInMemoryApiResources(Resources.GetApiResources())
                .AddInMemoryIdentityResources(Resources.GetIdentityResources())
                .AddInMemoryClients(Clients.Get())
                .AddTestUsers(Users.Get())
                .AddDeveloperSigningCredential();

        services.AddMvc();
    }

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

        app.UseDeveloperExceptionPage();//todo: add if debug

        app.UseIdentityServer();

        app.UseStaticFiles();

        app.UseMvcWithDefaultRoute();
    }
}

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

    public static IEnumerable<ApiResource> GetApiResources()
    {
        return new List<ApiResource> {
            new ApiResource("gateway", "Gateway Service")
        };
    }
}

internal class Clients
{
    public static IEnumerable<Client> Get()
    {
        return new List<Client> {
            new Client {
                ClientId = "gatewayClient",
                ClientSecrets = new List<Secret> { new Secret("password".Sha256())},//todo:secure password
                AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
                AllowedScopes = new List<string> { "gateway" }
            },
            new Client {
                ClientId = "gateway_implicitClient",
                ClientSecrets = new List<Secret> { new Secret("password".Sha256())},//todo:secure password
                AllowedGrantTypes = GrantTypes.Implicit,
                AllowedScopes = new List<string> {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    "gateway"
                },
                RedirectUris = new [] { "http://localhost:49942/signin-oidc" },
                PostLogoutRedirectUris = new [] { "http://localhost:49942/signout-callback-oidc" }
            }
        };
    }
}

internal class Users
{
    public static List<TestUser> Get()
    {
        return new List<TestUser> {
            new TestUser {
                SubjectId = "5BE86359-073C-434B-AD2D-A3932222DABE",
                Username = "scott",
                Password = "password"
            }
        };
    }
}

网页接口

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
        Configuration = builder.Build();

        _container = new Container();
    }

    public IConfigurationRoot Configuration { get; }
    private Container _container;

    public void ConfigureServices(IServiceCollection services)
    {
        AddAuthentication(services);
        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAntiforgery antiforgery)
    {
        app.UseAuthentication();
        app.UseMvc();
    }

    private void AddAuthentication(IServiceCollection services)
    {
        new IdentityServerConfig(services, Configuration);
    }
}

public class IdentityServerConfig
{
    public IdentityServerConfig(IServiceCollection services, IConfigurationRoot configuration)
    {
        services.AddMvcCore()
                .AddAuthorization()
                .AddJsonFormatters();

        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddIdentityServerAuthentication(options =>
                {
                    options.RequireHttpsMetadata = false;
                    options.Authority = "http://localhost:5000";
                    options.ApiName = "gateway_implicit";
                })
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddOpenIdConnect("oidc", options =>
                {
                    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.Authority = "http://localhost:5000";
                    options.RequireHttpsMetadata = false;
                    options.ClientId = "gateway_implicitClient";
                    options.SaveTokens = true;
                });
    }
}


[Produces("application/json")]
[Route("api/properties")]
public class PropertiesController : AuthController
{
    [HttpGet]
    [Route("GetProperty/{agentId}/{propertyId}")]
    public async Task<IActionResult> GetProperty(int agentId, Guid propertyId)
    {            
        return Ok(property);
    }
}

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace MyNameSpace.Controllers
{
    [Route("api/[controller]")]
    [Authorize]
    public class AuthController : ControllerBase
    {

    }
}

当我打电话时,http://localhost:49942/api/properties/GetPropertySummaries/1我可以在 VS 中看到以下输出

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: 请求开始 HTTP/1.1 GET http://localhost:49942/api/properties/GetPropertySummaries/1
'dotnet.exe' (CoreCLR: clrhost): 加载'C:\Users\me.nuget\packages\microsoft.aspnetcore.http.extensions\2.1.1\lib\netstandard2.0\Microsoft.AspNetCore.Http.Extensions。 dll'。跳过加载符号。模块已优化,调试器选项“仅我的代码”已启用。“dotnet.exe”(CoreCLR:clrhost):已加载“C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.1.6\System.ComponentModel.Annotations.dll”。跳过加载符号。模块已优化,调试器选项“仅我的代码”已启用。Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:信息:授权失败。Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:信息:过滤器“Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter”处的请求授权失败。微软。AspNetCore.Mvc.ChallengeResult:Information: 使用身份验证方案执行 ChallengeResult ()。“dotnet.exe”(CoreCLR:clrhost):已加载“C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.identitymodel.tokens\5.2.0\lib\netstandard1.4\Microsoft.IdentityModel.Tokens.dll”。跳过加载符号。模块已优化,调试器选项“仅我的代码”已启用。'dotnet.exe' (CoreCLR: clrhost): 加载'C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.identitymodel.tokens.jwt\5.2.0\lib\netstandard1.4\System.IdentityModel.Tokens.Jwt .dll'。跳过加载符号。模块已优化,调试器选项“仅我的代码”已启用。“dotnet.exe”(CoreCLR:clrhost):已加载“C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.1.6\System.Xml.ReaderWriter.dll”。跳过加载符号。模块已优化,调试器选项“仅我的代码”已启用。“dotnet.exe”(CoreCLR:clrhost):已加载“C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.identitymodel.logging\5.2.0\lib\netstandard1.4\Microsoft.IdentityModel.Logging.dll”。跳过加载符号。模块已优化,调试器选项“仅我的代码”已启用。“dotnet.exe”(CoreCLR:clrhost):已加载“C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.identitymodel.protocols\5.2.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.dll”。跳过加载符号。模块已优化,调试器选项“仅我的代码”已启用。“dotnet.exe”(CoreCLR:clrhost):已加载“C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.identitymodel.protocols。openidconnect\5.2.0\lib\netstandard1.4\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll'。跳过加载符号。模块已优化,调试器选项“仅我的代码”已启用。Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: AuthenticationScheme: BearerIdentityServerAuthenticationJwt 受到质疑。IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler:Information:AuthenticationScheme:Bearer 被质询。Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:信息:在 142.4256 毫秒内执行操作 MyNamespace.PropertiesController.GetPropertySummaries (MyService.Gateway.Service) Microsoft.AspNetCore.Hosting.Internal.WebHost:信息:请求在 526.0233 毫秒内完成 401 dll'。跳过加载符号。模块已优化,调试器选项“仅我的代码”已启用。Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: AuthenticationScheme: BearerIdentityServerAuthenticationJwt 受到质疑。IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler:Information:AuthenticationScheme:Bearer 被质询。Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:信息:在 142.4256 毫秒内执行操作 MyNamespace.PropertiesController.GetPropertySummaries (MyService.Gateway.Service) Microsoft.AspNetCore.Hosting.Internal.WebHost:信息:请求在 526.0233 毫秒内完成 401 dll'。跳过加载符号。模块已优化,调试器选项“仅我的代码”已启用。Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: AuthenticationScheme: BearerIdentityServerAuthenticationJwt 受到质疑。IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler:Information:AuthenticationScheme:Bearer 被质询。Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:信息:在 142.4256 毫秒内执行操作 MyNamespace.PropertiesController.GetPropertySummaries (MyService.Gateway.Service) Microsoft.AspNetCore.Hosting.Internal.WebHost:信息:请求在 526.0233 毫秒内完成 401 信息:AuthenticationScheme:BearerIdentityServerAuthenticationJwt 受到质疑。IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler:Information:AuthenticationScheme:Bearer 被质询。Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:信息:在 142.4256 毫秒内执行操作 MyNamespace.PropertiesController.GetPropertySummaries (MyService.Gateway.Service) Microsoft.AspNetCore.Hosting.Internal.WebHost:信息:请求在 526.0233 毫秒内完成 401 信息:AuthenticationScheme:BearerIdentityServerAuthenticationJwt 受到质疑。IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler:Information:AuthenticationScheme:Bearer 被质询。Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:信息:在 142.4256 毫秒内执行操作 MyNamespace.PropertiesController.GetPropertySummaries (MyService.Gateway.Service) Microsoft.AspNetCore.Hosting.Internal.WebHost:信息:请求在 526.0233 毫秒内完成 401

标签: asp.net-web-apiasp.net-web-api2identityserver4

解决方案


对于 API(而不是提供 HTML 的服务器端 Web 应用程序)返回 401 是正确的行为。这将向客户端(例如,javascript 客户端应用程序)发出它需要获取新令牌的信号。即,负责启动隐式/混合/任何登录流程以获取合适的不记名令牌的是所述 API 的客户端。

如果您采用 OpenID Connect/OAuth2 做事方式,那么您的 API 根本不会使用 cookie 进行身份验证,只会通过 AddIdentityServerAuthentication() 中间件使用不记名令牌身份验证。


推荐阅读