成功登錄後,Spring Security會重定向到上一頁


Answers

我想擴展Olcay的好答案。 他的方法很好,你的登錄頁面控制器應該像這樣把referrer url放入session:

@RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage(HttpServletRequest request, Model model) {
    String referrer = request.getHeader("Referer");
    request.getSession().setAttribute("url_prior_login", referrer);
    // some other stuff
    return "login";
}

您應該擴展SavedRequestAwareAuthenticationSuccessHandler並覆蓋其onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)方法。 像這樣的東西:

public class MyCustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    public MyCustomLoginSuccessHandler(String defaultTargetUrl) {
        setDefaultTargetUrl(defaultTargetUrl);
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
        HttpSession session = request.getSession();
        if (session != null) {
            String redirectUrl = (String) session.getAttribute("url_prior_login");
            if (redirectUrl != null) {
                // we do not forget to clean this attribute from session
                session.removeAttribute("url_prior_login");
                // then we redirect
                getRedirectStrategy().sendRedirect(request, response, redirectUrl);
            } else {
                super.onAuthenticationSuccess(request, response, authentication);
            }
        } else {
            super.onAuthenticationSuccess(request, response, authentication);
        }
    }
}

然後,在spring配置中,您應該將此自定義類定義為bean並在安全配置中使用它。 如果您使用的是註釋配置 ,它應該如下所示(您從WebSecurityConfigurerAdapter擴展的類):

@Bean
public AuthenticationSuccessHandler successHandler() {
    return new MyCustomLoginSuccessHandler("/yourdefaultsuccessurl");
}

configure方法中:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            // bla bla
            .formLogin()
                .loginPage("/login")
                .usernameParameter("username")
                .passwordParameter("password")
                .successHandler(successHandler())
                .permitAll()
            // etc etc
    ;
}
Question

我知道之前已經問過這個問題,但是我在這裡遇到了一個特殊的問題。

我使用spring security 3.1.3。

我的Web應用程序中有3個可能的登錄案例:

  1. 通過登錄頁面登錄:好的。
  2. 通過限制頁面登錄:也可以。
  3. 通過非限制性頁面登錄:不行......每個人都可以訪問“產品”頁面,如果用戶登錄,用戶可以發表評論。 因此,登錄表單包含在同一頁面中,以便允許用戶進行連接。

案例3)的問題是我無法將用戶重定向到“產品”頁面。 無論如何,他們會在成功登錄後重定向到主頁。

請注意,對於案例2),成功登錄後,重定向到受限頁面的工作開箱即用。

這是我的security.xml文件的相關部分:

<!-- Authentication policy for the restricted page  -->
<http use-expressions="true" auto-config="true" pattern="/restrictedPage/**">
    <form-login login-page="/login/restrictedLogin" authentication-failure-handler-ref="authenticationFailureHandler" />
    <intercept-url pattern="/**" access="isAuthenticated()" />
</http>

<!-- Authentication policy for every page -->
<http use-expressions="true" auto-config="true">
    <form-login login-page="/login" authentication-failure-handler-ref="authenticationFailureHandler" />
    <logout logout-url="/logout" logout-success-url="/" />
</http>

我懷疑“每個頁面的身份驗證策略”都要對此問題負責。 但是,如果我刪除它,我將無法再登錄... j_spring_security_check發送404錯誤。

編輯:

感謝拉爾夫,我找到了解決方案。 所以這就是事情:我使用了這個屬性

<property name="useReferer" value="true"/>

拉爾夫給我看了。 之後我遇到了我的案例問題1):當通過登錄頁面登錄時,用戶停留在同一頁面(並且沒有重定向到主頁,就像以前一樣)。 直到此階段的代碼如下:

<!-- Authentication policy for login page -->
<http use-expressions="true" auto-config="true" pattern="/login/**">
    <form-login login-page="/login" authentication-success-handler-ref="authenticationSuccessHandlerWithoutReferer" />
</http>

<!-- Authentication policy for every page -->
<http use-expressions="true" auto-config="true">
    <form-login login-page="/login" authentication-failure-handler-ref="authenticationFailureHandler" />
    <logout logout-url="/logout" logout-success-url="/" authentication-success-handler-ref="authenticationSuccessHandler"/>
</http>

<beans:bean id="authenticationSuccessHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
    <!-- After login, return to the last visited page -->
    <beans:property name="useReferer" value="true" />
</beans:bean>

<beans:bean id="authenticationSuccessHandlerWithoutReferer" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
    <!-- After login, stay to the same page -->
    <beans:property name="useReferer" value="false" />
</beans:bean>

至少在理論上這應該有效,但事實並非如此。 我仍然不知道為什麼,所以如果有人對此有答案,我很樂意創建一個新主題,讓他分享他的解決方案。

與此同時,我找到了解決方法。 不是最好的解決方案,但就像我說的,如果有人有更好的表現,我會全力以赴。 這是登錄頁面的新身份驗證策略:

<http use-expressions="true" auto-config="true" pattern="/login/**" >
    <intercept-url pattern="/**" access="isAnonymous()" />
    <access-denied-handler error-page="/"/>
</http>

這裡的解決方案非常明顯:只有匿名用戶才能使用登錄頁面。 連接用戶後,錯誤處理程序會將其重定向到主頁。

我做了一些測試,一切似乎都運行良好。




您可以使用自定義SuccessHandler擴展SimpleUrlAuthenticationSuccessHandler,以便在根據分配的角色登錄時將用戶重定向到不同的URL。

CustomSuccessHandler類提供自定義重定向功能:

package com.mycompany.uomrmsweb.configuration;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

@Component
public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler{

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Override
    protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        String targetUrl = determineTargetUrl(authentication);

        if (response.isCommitted()) {
            System.out.println("Can't redirect");
            return;
        }

        redirectStrategy.sendRedirect(request, response, targetUrl);
    }

    protected String determineTargetUrl(Authentication authentication) {
        String url="";

        Collection<? extends GrantedAuthority> authorities =  authentication.getAuthorities();

        List<String> roles = new ArrayList<String>();

        for (GrantedAuthority a : authorities) {
            roles.add(a.getAuthority());
        }

        if (isStaff(roles)) {
            url = "/staff";
        } else if (isAdmin(roles)) {
            url = "/admin";
        } else if (isStudent(roles)) {
            url = "/student";
        }else if (isUser(roles)) {
            url = "/home";
        } else {
            url="/Access_Denied";
        }

        return url;
    }

    public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
        this.redirectStrategy = redirectStrategy;
    }
    protected RedirectStrategy getRedirectStrategy() {
        return redirectStrategy;
    }

    private boolean isUser(List<String> roles) {
        if (roles.contains("ROLE_USER")) {
            return true;
        }
        return false;
    }

    private boolean isStudent(List<String> roles) {
        if (roles.contains("ROLE_Student")) {
            return true;
        }
        return false;
    }

    private boolean isAdmin(List<String> roles) {
        if (roles.contains("ROLE_SystemAdmin") || roles.contains("ROLE_ExaminationsStaff")) {
            return true;
        }
        return false;
    }

    private boolean isStaff(List<String> roles) {
        if (roles.contains("ROLE_AcademicStaff") || roles.contains("ROLE_UniversityAdmin")) {
            return true;
        }
        return false;
    }
}

擴展Spring SimpleUrlAuthenticationSuccessHandler類並覆蓋handle()方法,該方法只使用配置的RedirectStrategy [在本例中為default]調用重定向,並使用用戶定義的determineTargetUrl()方法返回的URL。 此方法從Authentication對像中提取當前登錄用戶的角色,然後根據角色構造適當的URL。 最後,RedirectStrategy負責Spring Security框架內的所有重定向,將請求重定向到指定的URL。

使用SecurityConfiguration類註冊CustomSuccessHandler:

package com.mycompany.uomrmsweb.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("customUserDetailsService")
    UserDetailsService userDetailsService;

    @Autowired
    CustomSuccessHandler customSuccessHandler;

    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
        .antMatchers("/", "/home").access("hasRole('USER')")
        .antMatchers("/admin/**").access("hasRole('SystemAdmin') or hasRole('ExaminationsStaff')")
        .antMatchers("/staff/**").access("hasRole('AcademicStaff') or hasRole('UniversityAdmin')")
        .antMatchers("/student/**").access("hasRole('Student')")  
                    .and().formLogin().loginPage("/login").successHandler(customSuccessHandler)
        .usernameParameter("username").passwordParameter("password")
        .and().csrf()
        .and().exceptionHandling().accessDeniedPage("/Access_Denied");
    }
}

successHandler是負責基於任何自定義邏輯的最終重定向的類,在這種情況下,它將根據用戶[USER / Student / SystemAdmin / UniversityAdmin / ExaminationsStaff / AcademicStaff]將用戶[重定向到學生/管理員/員工]。




以下通用解決方案可用於常規登錄,Spring Social登錄或大多數其他Spring Security過濾器。

在Spring MVC控制器中,加載產品頁面時,如果用戶尚未登錄,請在會話中保存產品頁面的路徑。在XML config中,設置默認目標URL。 例如:

在Spring MVC控制器中,重定向方法應從會話中讀出路徑並返回redirect:<my_saved_product_path>

因此,在用戶登錄後,它們將被發送到/redirect頁面,這將立即將它們重定向回他們上次訪問的產品頁面。




Links