[原創(chuàng)] IdentityServer4 登錄成功后跳轉(zhuǎn)發(fā)生錯誤
IdentityServer4官網(wǎng)自帶的DEMO,登錄成功后跳轉(zhuǎn)到請求網(wǎng)站,登錄過程是直接form提交的,我嫌棄官方的登錄不安全,字段明文發(fā)送,所以加了RSA加密,并把表單提交改為AJAX提交,于是后臺也相應(yīng)的做了代碼改動,結(jié)果大功告成的時候拿去登錄測試,出現(xiàn)以下的界面:
同時,在控制臺界面中輸出以下錯誤信息。
info: WinsWEB.Controllers.AccountController[0]
用戶成功登錄.
info: IdentityServer4.Hosting.IdentityServerMiddleware[0]
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeCallbackEndpoint for /connect/authorize/callback
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 6.0.10 initialized 'ConfigurationDbContext' using provider 'Microsoft.EntityFrameworkCore.Sqlite:6.0.10' with options: MigrationsAssembly=WinsWEB
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[@__clientId_0='?' (Size = 3)], CommandType='Text', CommandTimeout='30']
SELECT "c"."Id", "c"."AbsoluteRefreshTokenLifetime", "c"."AccessTokenLifetime", "c"."AccessTokenType", "c"."AllowAccessTokensViaBrowser", "c"."AllowOfflineAccess", "c"."AllowPlainTextPkce", "c"."AllowRememberConsent", "c"."AllowedIdentityTokenSigningAlgorithms", "c"."AlwaysIncludeUserClaimsInIdToken", "c"."AlwaysSendClientClaims", "c"."AuthorizationCodeLifetime", "c"."BackChannelLogoutSessionRequired", "c"."BackChannelLogoutUri", "c"."ClientClaimsPrefix", "c"."ClientId", "c"."ClientName", "c"."ClientUri", "c"."ConsentLifetime", "c"."Created", "c"."Description", "c"."DeviceCodeLifetime", "c"."EnableLocalLogin", "c"."Enabled", "c"."FrontChannelLogoutSessionRequired", "c"."FrontChannelLogoutUri", "c"."IdentityTokenLifetime", "c"."IncludeJwtId", "c"."LastAccessed", "c"."LogoUri", "c"."NonEditable", "c"."PairWiseSubjectSalt", "c"."ProtocolType", "c"."RefreshTokenExpiration", "c"."RefreshTokenUsage", "c"."RequireClientSecret", "c"."RequireConsent", "c"."RequirePkce", "c"."RequireRequestObject", "c"."SlidingRefreshTokenLifetime", "c"."UpdateAccessTokenClaimsOnRefresh", "c"."Updated", "c"."UserCodeType", "c"."UserSsoLifetime"
FROM "Clients" AS "c"
WHERE "c"."ClientId" = @__clientId_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[@__clientId_0='?' (Size = 3)], CommandType='Text', CommandTimeout='30']
SELECT "c0"."Id", "c0"."ClientId", "c0"."Origin"
FROM "Clients" AS "c"
INNER JOIN "ClientCorsOrigins" AS "c0" ON "c"."Id" = "c0"."ClientId"
WHERE "c"."ClientId" = @__clientId_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[@__clientId_0='?' (Size = 3)], CommandType='Text', CommandTimeout='30']
SELECT "c0"."Id", "c0"."ClientId", "c0"."GrantType"
FROM "Clients" AS "c"
INNER JOIN "ClientGrantTypes" AS "c0" ON "c"."Id" = "c0"."ClientId"
WHERE "c"."ClientId" = @__clientId_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[@__clientId_0='?' (Size = 3)], CommandType='Text', CommandTimeout='30']
SELECT "c0"."Id", "c0"."ClientId", "c0"."Scope"
FROM "Clients" AS "c"
INNER JOIN "ClientScopes" AS "c0" ON "c"."Id" = "c0"."ClientId"
WHERE "c"."ClientId" = @__clientId_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[@__clientId_0='?' (Size = 3)], CommandType='Text', CommandTimeout='30']
SELECT "c0"."Id", "c0"."ClientId", "c0"."Type", "c0"."Value"
FROM "Clients" AS "c"
INNER JOIN "ClientClaims" AS "c0" ON "c"."Id" = "c0"."ClientId"
WHERE "c"."ClientId" = @__clientId_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[@__clientId_0='?' (Size = 3)], CommandType='Text', CommandTimeout='30']
SELECT "c0"."Id", "c0"."ClientId", "c0"."Created", "c0"."Description", "c0"."Expiration", "c0"."Type", "c0"."Value"
FROM "Clients" AS "c"
INNER JOIN "ClientSecrets" AS "c0" ON "c"."Id" = "c0"."ClientId"
WHERE "c"."ClientId" = @__clientId_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[@__clientId_0='?' (Size = 3)], CommandType='Text', CommandTimeout='30']
SELECT "c0"."Id", "c0"."ClientId", "c0"."Provider"
FROM "Clients" AS "c"
INNER JOIN "ClientIdPRestrictions" AS "c0" ON "c"."Id" = "c0"."ClientId"
WHERE "c"."ClientId" = @__clientId_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[@__clientId_0='?' (Size = 3)], CommandType='Text', CommandTimeout='30']
SELECT "c0"."Id", "c0"."ClientId", "c0"."PostLogoutRedirectUri"
FROM "Clients" AS "c"
INNER JOIN "ClientPostLogoutRedirectUris" AS "c0" ON "c"."Id" = "c0"."ClientId"
WHERE "c"."ClientId" = @__clientId_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[@__clientId_0='?' (Size = 3)], CommandType='Text', CommandTimeout='30']
SELECT "c0"."Id", "c0"."ClientId", "c0"."Key", "c0"."Value"
FROM "Clients" AS "c"
INNER JOIN "ClientProperties" AS "c0" ON "c"."Id" = "c0"."ClientId"
WHERE "c"."ClientId" = @__clientId_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[@__clientId_0='?' (Size = 3)], CommandType='Text', CommandTimeout='30']
SELECT "c0"."Id", "c0"."ClientId", "c0"."RedirectUri"
FROM "Clients" AS "c"
INNER JOIN "ClientRedirectUris" AS "c0" ON "c"."Id" = "c0"."ClientId"
WHERE "c"."ClientId" = @__clientId_0
fail: IdentityServer4.Validation.AuthorizeRequestValidator[0]
redirect_uri is missing or too long
{
"ClientId": "mvc",
"AllowedRedirectUris": [
"https://localhost:5002/signin-oidc"
],
"SubjectId": "63c9887e-75eb-4099-b368-9d4fd6bf8299",
"RequestedScopes": "",
"PromptMode": "",
"Raw": {
"client_id": "mvc",
"amp;redirect_uri": "https://localhost:5002/signin-oidc",
"amp;response_type": "code",
"amp;scope": "openid profile webClaims",
"amp;code_challenge": "vLk6eGikeB7TTzTUva3VQVAOi0IcCLaP93d8Wsx-85s",
"amp;code_challenge_method": "S256",
"amp;response_mode": "form_post",
"amp;nonce": "638042572307173644.YjAxY2RhODctMTY2OS00ZDNjLWJmOWQtODNjYjFkMmE0MjBiMzZkZDJjYjctYjBhOS00Yzc1LTg3ODgtMGY4NzY2NmFlMzRj",
"amp;state": "CfDJ8IuGKdJpkDxNjX0iOT5Ekdac6izbbNBVp62kcZ5xyW5PITxN5tvou4bUpXawe8aR0D4h6fUFpB_4CNYGBKbEjCdwcjqKHtdBdDT2hAnrrhhG4keG6VmQrCPoaKwdsJChplAl6jUlfwSNrJzSaFTq0NwsSwwtGMVEZyiabaFLtXBKYUIn1EP9eGpW51WhBxjycRg_WzIQVHapW12EGA3OqPHkN0R693HtrkQps-wCzC6l3QrIQOV0kBN3JbSvY1FYXXhO3JM76U6msf-L0pXIwqfg01RWeoP8jeBiXvKVHLQ20zsmB0VrqD3ZUL-AfV-fldnYIp6ocMHw1yWQUqzHmnJwCG9kVCCtz8ZMI9LENGGL2rk0YSyK1EcRmKX0t3c4Qw",
"amp;x-client-SKU": "ID_NETSTANDARD2_0",
"amp;x-client-ver": "6.10.0.0"
}
}
fail: IdentityServer4.Endpoints.AuthorizeCallbackEndpoint[0]
Request validation failed
info: IdentityServer4.Endpoints.AuthorizeCallbackEndpoint[0]
{
"ClientId": "mvc",
"AllowedRedirectUris": [
"https://localhost:5002/signin-oidc"
],
"SubjectId": "63c9887e-75eb-4099-b368-9d4fd6bf8299",
"RequestedScopes": "",
"PromptMode": "",
"Raw": {
"client_id": "mvc",
"amp;redirect_uri": "https://localhost:5002/signin-oidc",
"amp;response_type": "code",
"amp;scope": "openid profile webClaims",
"amp;code_challenge": "vLk6eGikeB7TTzTUva3VQVAOi0IcCLaP93d8Wsx-85s",
"amp;code_challenge_method": "S256",
"amp;response_mode": "form_post",
"amp;nonce": "638042572307173644.YjAxY2RhODctMTY2OS00ZDNjLWJmOWQtODNjYjFkMmE0MjBiMzZkZDJjYjctYjBhOS00Yzc1LTg3ODgtMGY4NzY2NmFlMzRj",
"amp;state": "CfDJ8IuGKdJpkDxNjX0iOT5Ekdac6izbbNBVp62kcZ5xyW5PITxN5tvou4bUpXawe8aR0D4h6fUFpB_4CNYGBKbEjCdwcjqKHtdBdDT2hAnrrhhG4keG6VmQrCPoaKwdsJChplAl6jUlfwSNrJzSaFTq0NwsSwwtGMVEZyiabaFLtXBKYUIn1EP9eGpW51WhBxjycRg_WzIQVHapW12EGA3OqPHkN0R693HtrkQps-wCzC6l3QrIQOV0kBN3JbSvY1FYXXhO3JM76U6msf-L0pXIwqfg01RWeoP8jeBiXvKVHLQ20zsmB0VrqD3ZUL-AfV-fldnYIp6ocMHw1yWQUqzHmnJwCG9kVCCtz8ZMI9LENGGL2rk0YSyK1EcRmKX0t3c4Qw",
"amp;x-client-SKU": "ID_NETSTANDARD2_0",
"amp;x-client-ver": "6.10.0.0"
}
}
從提示來看,是返回地址出錯了,redirect_url為空或是太長,進(jìn)數(shù)據(jù)庫查看,配置是沒有問題的,從控制臺返回的信息來看,好奇怪,地址前面多了一個amp; ,一看明顯是轉(zhuǎn)換出現(xiàn)了問題,進(jìn)數(shù)據(jù)庫再次確認(rèn)查看,地址中不帶這個東西,打開后臺的代碼,仔細(xì)研究,如下:
/Account/Login 方法
....省略若干
if (result.Succeeded)
{
_logger.LogInformation("用戶成功登錄.");
if (context != null)
{
if (context.IsNativeClient())
{
// The client is native, so this change in how to
// return the response is for better UX for the end user.
return this.LoadingPage("Redirect", returnUrl);
}
// we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
//return Redirect(returnUrl);
return Json(new { result = "OK", msg = $"登錄成功.", returnUrl=returnUrl });
}
// request for a local page
if (Url.IsLocalUrl(returnUrl))
{
//return Redirect(returnUrl);
return Json(new { result = "OK", msg = $"登錄成功.", returnUrl = returnUrl });
}
如上所示,紅色的代碼已被我修改成綠色那一行。去前臺登錄處console.log(url) 輸出一下看看,得到下面跳轉(zhuǎn)地址:
/connect/authorize/callback?client_id=mvc&redirect_uri=https%3A%2F%2Flocalhost%3A5002%2Fsignin-oidc&response_type=code&scope=openid%20profile%20webClaims&code_challenge=vLk6eGikeB7TTzTUva3VQVAOi0IcCLaP93d8Wsx-85s&code_challenge_method=S256&response_mode=form_post&nonce=638042572307173644.YjAxY2RhODctMTY2OS00ZDNjLWJmOWQtODNjYjFkMmE0MjBiMzZkZDJjYjctYjBhOS00Yzc1LTg3ODgtMGY4NzY2NmFlMzRj&state=CfDJ8IuGKdJpkDxNjX0iOT5Ekdac6izbbNBVp62kcZ5xyW5PITxN5tvou4bUpXawe8aR0D4h6fUFpB_4CNYGBKbEjCdwcjqKHtdBdDT2hAnrrhhG4keG6VmQrCPoaKwdsJChplAl6jUlfwSNrJzSaFTq0NwsSwwtGMVEZyiabaFLtXBKYUIn1EP9eGpW51WhBxjycRg_WzIQVHapW12EGA3OqPHkN0R693HtrkQps-wCzC6l3QrIQOV0kBN3JbSvY1FYXXhO3JM76U6msf-L0pXIwqfg01RWeoP8jeBiXvKVHLQ20zsmB0VrqD3ZUL-AfV-fldnYIp6ocMHw1yWQUqzHmnJwCG9kVCCtz8ZMI9LENGGL2rk0YSyK1EcRmKX0t3c4Qw&x-client-SKU=ID_NETSTANDARD2_0&x-client-ver=6.10.0.0
看上去有點(diǎn)兒亂,找個在線網(wǎng)urldecode的地址轉(zhuǎn)碼一下,變成下面的會好看許多
/connect/authorize/callback?client_id=mvc&redirect_uri=https://localhost:5002/signin-oidc&response_type=code&scope=openid profile webClaims&code_challenge=vLk6eGikeB7TTzTUva3VQVAOi0IcCLaP93d8Wsx-85s&code_challenge_method=S256&response_mode=form_post&nonce=638042572307173644.YjAxY2RhODctMTY2OS00ZDNjLWJmOWQtODNjYjFkMmE0MjBiMzZkZDJjYjctYjBhOS00Yzc1LTg3ODgtMGY4NzY2NmFlMzRj&state=CfDJ8IuGKdJpkDxNjX0iOT5Ekdac6izbbNBVp62kcZ5xyW5PITxN5tvou4bUpXawe8aR0D4h6fUFpB_4CNYGBKbEjCdwcjqKHtdBdDT2hAnrrhhG4keG6VmQrCPoaKwdsJChplAl6jUlfwSNrJzSaFTq0NwsSwwtGMVEZyiabaFLtXBKYUIn1EP9eGpW51WhBxjycRg_WzIQVHapW12EGA3OqPHkN0R693HtrkQps-wCzC6l3QrIQOV0kBN3JbSvY1FYXXhO3JM76U6msf-L0pXIwqfg01RWeoP8jeBiXvKVHLQ20zsmB0VrqD3ZUL-AfV-fldnYIp6ocMHw1yWQUqzHmnJwCG9kVCCtz8ZMI9LENGGL2rk0YSyK1EcRmKX0t3c4Qw&x-client-SKU=ID_NETSTANDARD2_0&x-client-ver=6.10.0.0
OK,我們拿上面的地址去https://localhost:5001 這個IDS4地址去提交,也就是在瀏覽器地址欄粘上上面的地址,回車,注意觀察控制臺,報(bào)錯信息果斷出現(xiàn)了,看來就是這里編碼轉(zhuǎn)換出錯了,錯誤的把&變成& ,引起程序不能正確識別URL引起的,我們替換處理一下,再在瀏覽器提交,發(fā)現(xiàn)正常跳轉(zhuǎn),至此,問題完美解決。