【问题标题】:Redirect to same URL at client side after authentication from token server (identity server 4)从令牌服务器(身份服务器 4)进行身份验证后重定向到客户端的相同 URL
【发布时间】:2020-02-05 08:54:32
【问题描述】:

我将身份服务器 4 用于用户身份和令牌服务。我的客户端应用程序是用 .Net core React 模板编写的。一切正常,但是当最终用户点击客户端子 URL 页面(从电子邮件接收)时,它会重定向到 STS 身份服务器进行身份验证并返回主页而不是用户点击 URL 的子页面乞讨。

例如,当用户点击客户端 URL(https://localhost:44309/bills)(which 是通过电子邮件接收)时,它会进入 (https://localhost:44318/Login) 的登录页面,并且在用户身份验证后,它会重定向到 (https://localhost:44309/Home) 而不是 (https://localhost:44309/bills) .

我使用了类似于下面链接的 Identity server 4 代码

https://github.com/damienbod/IdentityServer4AspNetCoreIdentityTemplate/tree/master/content/StsServerIdentity

身份服务器添加客户端


{
        "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/"
  },

身份服务器端代码。类似于https://github.com/IdentityServer/IdentityServer4.Demo/blob/master/src/IdentityServer4Demo/Quickstart/Account/AccountController.cs

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 asp.net-core identityserver4


    【解决方案1】:

    你必须在reactjs中使用history来获取之前的路径并且需要保存在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;
    

    【讨论】:

    • 谢谢@niks 是的,我可以做会话存储。但是有什么方法可以从身份服务器(令牌服务器)返回之前从客户端命中的 URL 来处理它?
    猜你喜欢
    • 2012-08-28
    • 1970-01-01
    • 2019-12-01
    • 1970-01-01
    • 2011-11-04
    • 2020-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多