form-login配置中的authentication-success-handler-ref可以讓手動注入登錄成功后的處理程序,需要實現AuthenticationSuccessHandler接口。
~~~
<sec:form-login login-page="/login.jsp"
login-processing-url="/login.do"
authentication-failure-url="/login.jsp"
authentication-success-handler-ref="authenticationSuccessHandler"
/>
~~~
springSecurity默認的登錄用戶驗證路徑為:j_spring_security_check,這個路徑是可以通過login-processing-url來自己定義,比如我的就定義成了login.do。
然后在前臺登錄頁面中改下form中的action就可以了。
配置文件,注意這里的defaultTargetUrl,本來這個是在form-login中,配置的但是如果我們自己定義登錄成功后的處理程序后它就不起作用了,所以這個跳轉也需要我們在自定義程序中處理。
~~~
<bean id="authenticationSuccessHandler" class="com.zrhis.system.security.SimpleLoginSuccessHandler">
<property name="defaultTargetUrl" value="/WEB-INF/app.jsp"></property>
<property name="forwardToDestination" value="true"></property>
</bean>
~~~
SimpleLoginSuccessHandler,這個類主要處理登錄后的處理,我處理的是登錄后記錄用戶的IP地址和登錄時間,代碼如下?
~~~
package com.zrhis.system.security;
import java.io.IOException;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import com.zrhis.base.exception.InitializationException;
import com.zrhis.system.bean.SysUsers;
import com.zrhis.system.repository.SysUsersRepository;
public class SimpleLoginSuccessHandler implements AuthenticationSuccessHandler,InitializingBean {
protected Log logger = LogFactory.getLog(getClass());
private String defaultTargetUrl;
private boolean forwardToDestination = false;
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Autowired
private SysUsersRepository sysUsersRepository;
/* (non-Javadoc)
* @see org.springframework.security.web.authentication.AuthenticationSuccessHandler#onAuthenticationSuccess(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication)
*/
@Override
@Transactional(readOnly=false,propagation= Propagation.REQUIRED,rollbackFor={Exception.class})
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
this.saveLoginInfo(request, authentication);
if(this.forwardToDestination){
logger.info("Login success,Forwarding to "+this.defaultTargetUrl);
request.getRequestDispatcher(this.defaultTargetUrl).forward(request, response);
}else{
logger.info("Login success,Redirecting to "+this.defaultTargetUrl);
this.redirectStrategy.sendRedirect(request, response, this.defaultTargetUrl);
}
}
@Transactional(readOnly=false,propagation= Propagation.REQUIRED,rollbackFor={Exception.class})
public void saveLoginInfo(HttpServletRequest request,Authentication authentication){
SysUsers user = (SysUsers)authentication.getPrincipal();
try {
String ip = this.getIpAddress(request);
Date date = new Date();
user.setLastLogin(date);
user.setLoginIp(ip);
this.sysUsersRepository.saveAndFlush(user);
} catch (DataAccessException e) {
if(logger.isWarnEnabled()){
logger.info("無法更新用戶登錄信息至數據庫");
}
}
}
public String getIpAddress(HttpServletRequest request){
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
public void setDefaultTargetUrl(String defaultTargetUrl) {
this.defaultTargetUrl = defaultTargetUrl;
}
public void setForwardToDestination(boolean forwardToDestination) {
this.forwardToDestination = forwardToDestination;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
if(StringUtils.isEmpty(defaultTargetUrl))
throw new InitializationException("You must configure defaultTargetUrl");
}
}
~~~
其中getIpAddress方法摘自網絡,如有雷同純屬必然。
實現InitializingBean,在afterPropertiesSet中我們驗證defaultTargetUrl是否為空,如果為空就拋出異常,因為這個地址是必須的。可以根據自己的情況來選擇要不要加驗證。
如果實現InitializingBean在程序啟動是Spring在創建完這個類并注入屬性后會自動執行afterPropertiesSet,所以我們的一些初始化的操作也是可以在這里完成的。
onAuthenticationSuccess是主要的接口這個是登錄成功后Spring調用的方法,而我們的跳轉和保存用戶信息都是在這里完成的。
RedirectStrategy是Spring提供的一個客戶端跳轉的工具類。使用它可以支持“/index.jsp”這種地址,同時可以保證服務器跳轉和客戶端跳轉的路徑一致。
加入我們的項目名為my ,項目訪問地址為http://localhost:8080/my
現在要使用客戶端跳轉到 "/login.jsp" 如果是response.sendRedirect 會直接跳轉到http://localhost:8080/login.jsp
而使用redirectStrategy.sendRedirect則會跳轉到http://localhost:8080/my/login.jsp
在redirectStrategy中,'/'代表的是項目根目錄而不是服務器根目錄。
- 前言
- (大綱)----學習過程分享
- (1)----SpringSecurity3.2環境搭建
- (2)----SpringSecurity簡單測試
- (3)---- 自定義登錄頁面
- (4)---- 數據庫表結構的創建
- (5)---- 國際化配置及UserCache
- (6)---- 使用數據庫管理用戶及權限
- (7)---- 解決UsernameNotFoundException無法被捕獲的問題
- (8)---- 自定義決策管理器及修改權限前綴
- (9)---- 自定義AccessDeniedHandler
- (10)---- 自定義登錄成功后的處理程序及修改默認驗證地址
- (11)---- 使用數據庫來管理資源
- (12)---- 使用數據庫來管理方法
- (13)---- 驗證碼功能的實現
- (14)---- Logout和SessionManager