我正在尝试使用身份服务器和Web Api实现SSO
到目前为止,我已经创建了一个身份服务器项目和一个Web Api项目,并根据我遵循的Pluralsight course对其进行了配置。自创建此课程以来,似乎已经发生了一些变化,因此我必须做的某些操作与本教程不符(这可能是造成我痛苦的原因,但我认为不是)。>
我希望发生的是,我遇到了一个需要授权的控制器,并且如果需要,我将被重定向到Identity Server登录页面。目前我收到了401。我查看了implicit flow here的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"
}
};
}
}
Web API
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:信息:请求启动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”。跳过的加载符号。模块已优化,调试器选项“ Just My Code”已启用。 'dotnet.exe'(CoreCLR:clrhost):已加载'C:\ Program Files \ dotnet \ shared \ Microsoft.NETCore.App \ 2.1.6 \ System.ComponentModel.Annotations.dll'。跳过的加载符号。模块已优化,调试器选项“ Just My Code”已启用。 Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:信息:授权失败。 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:信息:过滤器“ Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter”上的请求授权失败。 Microsoft.AspNetCore.Mvc.ChallengeResult:信息:使用身份验证方案()执行ChallengeResult。 'dotnet.exe'(CoreCLR:clrhost):已加载'C:\ Program Files \ dotnet \ sdk \ NuGetFallbackFolder \ microsoft.identitymodel.tokens \ 5.2.0 \ lib \ netstandard1.4 \ Microsoft.IdentityModel.Tokens.dll'。跳过的加载符号。模块已优化,调试器选项“ Just My Code”已启用。 '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”。跳过的加载符号。模块已优化,调试器选项“ Just My Code”已启用。 'dotnet.exe'(CoreCLR:clrhost):已加载'C:\ Program Files \ dotnet \ shared \ Microsoft.NETCore.App \ 2.1.6 \ System.Xml.ReaderWriter.dll'。跳过的加载符号。模块已优化,调试器选项“ Just My Code”已启用。 'dotnet.exe'(CoreCLR:clrhost):已加载'C:\ Program Files \ dotnet \ sdk \ NuGetFallbackFolder \ microsoft.identitymodel.logging \ 5.2.0 \ lib \ netstandard1.4 \ Microsoft.IdentityModel.Logging.dll'。跳过的加载符号。模块已优化,调试器选项“ Just My Code”已启用。 'dotnet.exe'(CoreCLR:clrhost):已加载'C:\ Program Files \ dotnet \ sdk \ NuGetFallbackFolder \ microsoft.identitymodel.protocols \ 5.2.0 \ lib \ netstandard1.4 \ Microsoft.IdentityModel.Protocols.dll。跳过的加载符号。模块已优化,调试器选项“ Just My Code”已启用。 '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”。跳过的加载符号。模块已优化,调试器选项“ Just My Code”已启用。 Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:信息:AuthenticationScheme:BearerIdentityServerAuthenticationJwt被质疑。 IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler:信息:AuthenticationScheme:承载被质询。 Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information:执行的动作MyNamespace.PropertiesController.GetPropertySummaries(MyService.Gateway.Service)在142.4256毫秒内 Microsoft.AspNetCore.Hosting.Internal.WebHost:信息:请求在526.0233ms中完成401
答案 0 :(得分:2)
对于API(而不是服务于HTML的服务器端Web应用程序),返回401是正确的行为。这将通知客户端(例如javascript客户端应用程序)需要获取新令牌。即正是该API的客户端负责启动隐式/混合/无论何种登录流程,以获取合适的承载令牌。
如果您采用的是OpenID Connect / OAuth2处理方式,则您的API根本不会使用Cookie进行身份验证,而只会通过AddIdentityServerAuthentication()中间件使用承载令牌身份验证。