无法使用“/connect/authorize”端点从 IdentityServer4 获取授权码
Posted
技术标签:
【中文标题】无法使用“/connect/authorize”端点从 IdentityServer4 获取授权码【英文标题】:Cannot get Authorization Code from IdentityServer4 using "/connect/authorize" endpoint 【发布时间】:2021-11-04 09:13:21 【问题描述】:我正在开发一个 SPA 应用程序,其 Identityserver4 介于 Angular 和 .net API 之间。身份服务器的大部分配置都已完成,唯一的障碍是,当我调用 /connect/authorize 时,我没有获得授权代码,我得到了带有我提供的数据的编码重定向 URL。我错过了什么吗?我真的无法理解为什么会有这种行为。
Postman screenshot
这是客户端配置
new Client
ClientId = "Angular",
ClientName = "Angular Client",
AlwaysIncludeUserClaimsInIdToken = true,
AllowedGrantTypes = new List<string> GrantType.AuthorizationCode ,
RequirePkce =true,
RequireClientSecret = false,
RequireConsent = false,
ClientSecrets =
new Secret("secret".Sha512(),"my secret")
,
AllowedScopes = "WebAPI","fullcontroll",IdentityServerConstants.StandardScopes.OpenId,
Claims = new List<ClientClaim>
new ClientClaim("clientName", "SPA"),
,
RedirectUris = "https://localhost:6001/login" ,
FrontChannelLogoutUri = "https://localhost:4001/signout-oidc",
PostLogoutRedirectUris = "http://localhost:4001/signout-callback-oidc" ,
AllowedCorsOrigins = new List<string>
"https://localhost:4001",
"https://localhost:5001",
"https://localhost:6001",
,
AllowOfflineAccess =true,
AccessTokenLifetime = 3600,
IdentityTokenLifetime = 300,
AlwaysSendClientClaims = true,
Enabled = true
,
Startup.cs
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<IdentityServerContext>()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddUserManager<UserManager<ApplicationUser>>()
.AddSignInManager<SignInManager<ApplicationUser>>()
.AddDefaultTokenProviders();
services.ConfigDbContext(Configuration);
services.InjectClients(Configuration);
services.AddAuthentication(options =>
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
options.DefaultForbidScheme = OpenIdConnectDefaults.AuthenticationScheme;
options.RequireAuthenticatedSignIn = true;
)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
options.Cookie.Name = "login-vault";
options.Cookie.SameSite = SameSiteMode.Lax;
//options.LoginPath = "/identityserver/login";
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
options.Cookie.SecurePolicy = 0;
options.SlidingExpiration = true;
options.Events.OnSigningOut = async e =>
// revoke refresh token on sign-out
await e.HttpContext.RevokeUserRefreshTokenAsync();
;
)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
options.Authority = "https://localhost:4001";
options.ClientId = "Angular";
options.ClientSecret = "secret";
options.Resource = "WebAPI";
options.ResponseType = "code";
try
var oidc = Registry.CurrentUser.OpenSubKey(@"Keys", true).OpenSubKey(@"IdentityServer", true).CreateSubKey("OIDC", true);
options.DataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo(oidc.ToString()),
options =>
options.UseCryptographicAlgorithms(
new AuthenticatedEncryptorConfiguration()
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA512
)
.SetDefaultKeyLifetime(TimeSpan.FromDays(30))
.PersistKeysToRegistry(Registry.CurrentUser.OpenSubKey(@"Keys", true).OpenSubKey(@"IdentityServer", true).OpenSubKey(@"OIDC", true))
.ProtectKeysWithDpapi();
)
.CreateProtector("WebAPI");
catch (Exception e)
Console.WriteLine(e.Message);
options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
options.UseTokenLifetime = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.UsePkce = true;
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.Scope.Add("WebAPI");
options.Scope.Add("offline_access");
options.CallbackPath = "/signin-odic";
options.SignedOutRedirectUri = "https://localhost:4001/connect/endsession";
options.TokenValidationParameters = new TokenValidationParameters
NameClaimType = "name",
RoleClaimType = "role"
;
);
services.AddAccessTokenManagement(options =>
options.Client.Scheme = OpenIdConnectDefaults.AuthenticationScheme;
options.User.Scheme = OpenIdConnectDefaults.AuthenticationScheme;
);
services.AddClientAccessTokenClient("Angular", configureClient: client =>
client.BaseAddress = new Uri("https://localhost:5001/api/"));
services.AddUserAccessTokenClient("ApplicationUsers", client =>
client.BaseAddress = new Uri("https://localhost:5001/api/");
);
这是 IdentityServer 配置
services.AddIdentityServer(options =>
options.Authentication.CookieLifetime = TimeSpan.FromMinutes(5);
options.Authentication.CookieSameSiteMode = SameSiteMode.Lax;
options.Authentication.CookieSlidingExpiration = true;
//options.Authentication.CheckSessionCookieName = "Identity.Session";
options.EmitStaticAudienceClaim = true;
options.IssuerUri = "https://localhost:4001";
options.LowerCaseIssuerUri = true;
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
options.EmitScopesAsSpaceDelimitedStringInJwt = false;
options.Endpoints.EnableCheckSessionEndpoint = true;
options.Endpoints.EnableEndSessionEndpoint = true;
options.Endpoints.EnableTokenEndpoint = true;
options.Endpoints.EnableAuthorizeEndpoint = true;
options.Endpoints.EnableJwtRequestUri = true;
options.UserInteraction.LoginUrl = "https://localhost:6001/login";
options.UserInteraction.LogoutUrl = "https://localhost:6001/logout";
//options.UserInteraction.ConsentUrl = "";
)
.AddAspNetIdentity<ApplicationUser>()
.AddDeveloperSigningCredential()
//.AddSigningCredential(new X509Certificate2(Path.Combine(".", "certs", "IdentityServer4Auth.pfx")))
.AddConfigurationStore(options =>
options.ConfigureDbContext = b => b.UseSqlServer(configuration.GetConnectionString("IdentityServer"),
sql => sql.MigrationsAssembly(migrationAssembly));
)
.AddOperationalStore(options =>
options.ConfigureDbContext = b => b.UseSqlServer(configuration.GetConnectionString("IdentityServer"),
sql => sql.MigrationsAssembly(migrationAssembly));
options.EnableTokenCleanup = false;
options.TokenCleanupInterval = 3600;
);
非常感谢您的帮助! 谢谢!
【问题讨论】:
请修剪您的代码,以便更容易找到您的问题。请按照以下指南创建minimal reproducible example。 【参考方案1】:授权端点旨在在浏览器内调用(通常是 GET 请求,但也支持通过表单的 POST)。这样,如果需要交互式身份验证,端点可以重定向到该 UI,然后在完成后继续为请求提供服务。
您的 identityserver4
实例配置为使用 https://localhost:6001/login
进行身份验证,这就是为什么您会看到 302 重定向到该 URL - 授权端点看到用户未经身份验证(不存在 cookie)并自动重定向到options.UserInteraction.LoginUrl
的值。
【讨论】:
以上是关于无法使用“/connect/authorize”端点从 IdentityServer4 获取授权码的主要内容,如果未能解决你的问题,请参考以下文章
带有 docker-compose 的 Identity Server 4 在 /connect/authorize/callback 之后重定向到登录页面