reactjs - 从令牌服务器(身份服务器 4)进行身份验证后重定向到客户端的相同 URL
问题描述
我将身份服务器 4 用于用户身份和令牌服务。我的客户端应用程序是用 .Net core React 模板编写的。一切正常,但是当最终用户点击客户端子 URL 页面(从电子邮件接收)时,它会重定向到 STS 身份服务器进行身份验证并返回主页而不是用户点击 URL 的子页面乞讨。
例如,当用户点击客户端 URL(https://localhost:44309/bills )(通过电子邮件接收)时,它将进入(https://localhost:44318/Login)的登录页面,并且在用户身份验证后重定向到( https://localhost:44309/Home ) 而不是 ( https://localhost:44309/bills )。
我使用了类似于以下链接的 Identity server 4 代码
身份服务器添加客户端
{
"ClientId": "reactclient",
"ClientName": "React Client",
"Enabled": true,
"RequireClientSecret": false,
"EnableLocalLogin": true,
"RequireConsent": false,
"AllowedGrantTypes": [ "authorization_code", "hybrid", "client_credentials" ],
"RedirectUris": [ "https://localhost:44309/signin-oidc" ],
"PostLogoutRedirectUris": [ "https://localhost:44309/logout/callback" ],
"AccessTokenType": "Jwt",
"AllowAccessTokensViaBrowser": true,
//"UpdateAccessTokenClaimsOnRefresh": true,
"AllowOfflineAccess": true,
"AccessTokenLifetime": 14400,
"IdentityTokenLifetime": 7200,
"AllowedScopes": [
"openid",
"profile",
"email",
"offline_access"
]
}
客户端
export const IDENTITY_CONFIG = {
authority: process.env.REACT_APP_AUTH_URI,
client_id: process.env.REACT_APP_IDENTITY_CLIENT_ID,
redirect_uri: process.env.REACT_APP_BASE_URI + process.env.REACT_APP_REDIRECT_PATH,
automaticSilentRenew: true,
filterProtocolClaims: true,
loadUserInfo: true,
silent_redirect_uri: process.env.REACT_APP_BASE_URI + process.env.REACT_APP_SILENT_REDIRECT_PATH,
post_logout_redirect_uri: process.env.REACT_APP_BASE_URI + process.env.REACT_APP_LOGOFF_REDIRECT_PATH,
response_type: 'code',
scope: process.env.REACT_APP_SCOPE
};
"base": {
"REACT_APP_TESTENV": "1",
"REACT_APP_IDENTITY_CLIENT_ID": "reactclient",
"REACT_APP_REDIRECT_PATH": "signin-oidc",
"REACT_APP_SILENT_REDIRECT_PATH": "silentrenew",
"REACT_APP_LOGOFF_REDIRECT_PATH": "logout/callback",
"REACT_APP_SCOPE": "openid profile email",
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
},
"development": {
"REACT_APP_TESTENV": "development",
"REACT_APP_AUTH_URI": "https://localhost:44318",
"REACT_APP_AUTH_ISSUER": "https://localhost:44318",
"REACT_APP_BASE_URI": "https://localhost:44309/",
"REACT_APP_SERVICE_MEMBER_BASE_URI": "https://localhost:44320/"
},
public async Task<IActionResult> Login(LoginInputModel model)
{
var returnUrl = model.ReturnUrl;
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
//
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberLogin, lockoutOnFailure: false);
if (result.Succeeded)
{
Logit("User logged in.");
return RedirectToLocal(returnUrl);
}
else if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(VerifyCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberLogin });
}
else if (result.IsLockedOut)
{
Logit("User account locked out.");
return View("Lockout");
}
else
{
//check if user exists in BIZZ db
ModelState.AddModelError(string.Empty, _sharedLocalizer["INVALID_LOGIN_ATTEMPT"]);
return View(await BuildLoginViewModelAsync(model));
}
}
// If we got this far, something failed, redisplay form
return View(await BuildLoginViewModelAsync(model));
}
谁能解释我如何在每次登录后重定向到特定页面而不是每次都转到主页。我想在身份服务器而不是客户端解决这个问题。
解决方案
您必须使用 reactjs 中的历史来获取以前的路径,并且需要保存在 sessionStorage 中。
可能这会帮助你:
const SAVED_URI = 'APP_PLU';
const FORBIDDEN_URIS = ['/login-response', '/'];
const DEFAULT_URI = '/';
function setPostLoginUri() {
// using just the pathname for demo, should be more detailed in production to
// include query params, hash bangs, etc
const currentPath = window.location.pathname;
const savedURI = sessionStorage.getItem(SAVED_URI);
if (FORBIDDEN_URIS.includes(currentPath) || savedURI) {
return;
}
sessionStorage.setItem(SAVED_URI, currentPath);
}
function getPostLoginUri(retain) {
const savedURI = sessionStorage.getItem(SAVED_URI);
if (!retain) {
sessionStorage.removeItem(SAVED_URI);
}
return savedURI || DEFAULT_URI;
}
export default {
get: getPostLoginUri,
set: setPostLoginUri
};
并在 app.js 中设置
然后在您的登录响应页面中添加此代码,
function LoginResponse({ history, setUser }) {
const [error, setError] = useState(null);
useEffect(() => {
// the login redirect has been completed and we call the
// signinRedirectCallback to fetch the user data
userManager.signinRedirectCallback().then(user => {
// received the user data so we set it in the app state and push the
// router to the secure or bookmarked route
setUser(user);
history.push(postLoginUri.get());
}, ({ message }) => {
// userManager throws if someone tries to access the route directly or if
// they refresh on a failed request so we just send them to the app root
if (message && redirectErrors.includes(message)) {
history.push('/');
return;
}
// for all other errors just display the message in production it would be
// a good idea to initiate a sign out after a countdown
setError(message);
});
}, []);
return error;
}
export default LoginResponse;
推荐阅读
- flutter - 如何将我的后台通知添加到 Hive 框中?如何在静态方法中初始化 Hive 框?
- python - 整数子类哈希
- python - C++(libtorch)中的Python数组切片是否有类比?
- apache-flink - 在 flink 中如何验证给定窗口中是否没有收到相同的用户数据?
- flutter - 以下 UI 的 GridView 问题
- r - R 无法从 github 下载 websockets 包
- asp.net-mvc - 多态模型绑定/复杂模型
- c++ - 视觉 C++。LNK2011:未链接的预编译对象。但我链接
- python - 如何对搜索栏的结果进行分页并避免破坏 Flask?
- google-cloud-dataflow - GCP Pub/Sub 订阅者未在 Apache Dataflow 管道中接收消息