1. 概述
網站通常會阻止用户在已登錄狀態下訪問登錄頁面。 常見的做法是將其重定向到另一個頁面,通常是登錄後應用程序的起始點。
在本教程中,我們將探索使用 Spring Security 實施此解決方案的多種方法。
為了更深入地瞭解如何快速實現登錄,我們可以從這篇文章開始。
2. 身份驗證驗證
首先,我們需要一種驗證身份驗證的方法。
換句話説,我們需要從 SecurityContext 中獲取身份驗證詳情,並驗證用户是否已登錄:
private boolean isAuthenticated() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || AnonymousAuthenticationToken.class.
isAssignableFrom(authentication.getClass())) {
return false;
}
return authentication.isAuthenticated();
}我們將在此處使用的,在所有負責重定向的組件中。
3. 從登錄控制器重定向
最簡單的方法是定義登錄頁面的端點,在控制器中實現。
我們需要在用户已認證時返回特定的頁面,否則返回登錄頁面。
@GetMapping("/loginUser")
public String getUserLoginPage() {
if (isAuthenticated()) {
return "redirect:userMainPage";
}
return "loginUser";
}4. 使用攔截器
通過登錄頁面的 URI 上攔截器,另一種重定向用户的方式是
攔截器會在請求到達控制器之前攔截該請求。因此,我們可以根據身份驗證情況決定是否繼續處理請求,或者阻止請求並返回重定向響應。
如果用户已認證,我們需要修改響應中的兩個內容:
- 將狀態碼設置為 HttpStatus.SC_TEMPORARY_REDIRECT
- 添加 Location 標頭,並使用重定向 URL
最後,我們將通過返回 false 來中斷執行鏈:
public class LoginPageInterceptor implements HandlerInterceptor {
UrlPathHelper urlPathHelper = new UrlPathHelper();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if ("/loginUser".equals(urlPathHelper.getLookupPathForRequest(request)) && isAuthenticated()) {
String encodedRedirectURL = response.encodeRedirectURL(
request.getContextPath() + "/userMainPage");
response.setStatus(HttpStatus.SC_TEMPORARY_REDIRECT);
response.setHeader("Location", encodedRedirectURL);
return false;
} else {
return true;
}
}
// isAuthenticated method
}我們需要將攔截器添加到 Spring MVC 生命週期中:
@Configuration
public class LoginRedirectMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginPageInterceptor());
}
}
我們也可以使用 Spring 的基於 XML 模式的配置來實現相同的結果:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/loginUser"/>
<bean class="com.baeldung.loginredirect.LoginPageInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>5. 使用過濾器
類似地,我們可以實現一個 Spring 過濾器。
該過濾器可以直接應用於 SecurityContext,利用 Spring Security 的過濾器鏈。因此,它可以在身份驗證創建後立即攔截請求。
讓我們擴展 GenericFilterBean,覆蓋 doFilter 方法,並驗證身份驗證:
public class LoginPageFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest servletRequest = (HttpServletRequest) request;
HttpServletResponse servletResponse = (HttpServletResponse) response;
if (isAuthenticated() && "/loginUser".equals(servletRequest.getRequestURI())) {
String encodedRedirectURL = ((HttpServletResponse) response).encodeRedirectURL(
servletRequest.getContextPath() + "/userMainPage");
servletResponse.setStatus(HttpStatus.SC_TEMPORARY_REDIRECT);
servletResponse.setHeader("Location", encodedRedirectURL);
}
chain.doFilter(servletRequest, servletResponse);
}
// isAuthenticated method
}我們需要在過濾器鏈中添加過濾器,位於 UsernamePasswordAuthenticationFilter 之後。
此外,我們需要授權登錄頁 URI 的請求,以便為該請求啓用過濾器鏈:
@Configuration
@EnableWebSecurity
public class LoginRedirectSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.addFilterAfter(new LoginPageFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
authorizationManagerRequestMatcherRegistry.requestMatchers("/loginUser").permitAll()
// Other security configuration
}
}
最後,如果選擇使用XML配置,我們可以為過濾器定義Bean,並將其添加到安全 HTTP 標籤中的過濾器鏈中:
<beans:bean id="loginPageFilter" class="com.baeldung.loginredirect.LoginPageFilter"/>
<security:http pattern="/**" use-expressions="true" auto-config="true">
<security:intercept-url pattern="/loginUser" access="permitAll"/>
<security:custom-filter after="BASIC_AUTH_FILTER" ref="loginPageFilter"/>
</security:http>關於如何為 Spring Security 創建自定義過濾器的快速教程,請參考這裏。
6. 結論
在本教程中,我們探討了多種使用 Spring Security 從登錄頁面重定向已登錄用户的技巧。
另一個可能對您有幫助的教程是“使用 Spring Security 在登錄後重定向到不同頁面”,其中我們學習瞭如何將不同類型的用户重定向到特定的頁面。