Spring Security修煉手冊(三)————Security個性化認證流程

    在第二章節,咱們主要學習了Security的自定義認證的實現和認證的流程,同時也存在一些問題,好比咱們想在用戶認證成功或失敗後記錄日誌等相關操做,咱們怎麼辦呢?別擔憂,Security已經爲咱們想好了,咱們只須要實現其提供的接口並配置便可。html

1、 自定義登陸成功處理  

    AuthenticationSuccessHandle是Security提供的認證成功處理器接口,代碼以下:前端

    如今咱們具體實現如下,好比咱們在用戶認證成功後,打印一段某某用戶在什麼時間登陸成功的日誌,並返回給前端頁面當前用戶的認證信息:java

import java.io.IOException;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.ObjectMapper;

@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
		
	private Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private ObjectMapper objectMapper;
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		// TODO Auto-generated method stub
		logger.info(authentication.getName()+"在"+new Date()+"登陸成功");
		response.setContentType("application/json;charset=UTF-8");
		response.getWriter().write(objectMapper.writeValueAsString(authentication));

	}

}

    而後咱們須要將認證成功處理器在SecurityConfig中配置一下:web

啓動項目,再次登陸,web界面顯示以下:spring

     咱們能夠看到Authentication中有當前用戶的權限、Session、名字等等信息,Authentication就是認證成功後Security爲咱們提供的一個封裝,裏面具體都有什麼屬性,感興趣的朋友能夠具體去看這個接口,這裏不作詳述。數據庫

        後臺Log輸出以下:json

2、 自定義認證失敗處理  

        經過名字你們應該能夠猜出Security提供的失敗處理器的名字叫作:AuthenticationFailureHandler,app

這個處理器和成功處理器仍是有區別的,成功處理器方法中最後一個參數是封裝好的用戶認證信息,而失敗處理器最後一個參數是在UserDetailServer中所捕獲到的異常信息。能夠看下我實現的邏輯:打印拋出的異常信息。框架

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {

	private Logger logger = LoggerFactory.getLogger(getClass());
	/* (non-Javadoc)
	 * @see org.springframework.security.web.authentication.AuthenticationFailureHandler#onAuthenticationFailure(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.AuthenticationException)
	 */
	@Override
	public void onAuthenticationFailure(HttpServletRequest arg0, HttpServletResponse response, AuthenticationException authentication)
			throws IOException, ServletException {
		
		logger.info(authentication.getMessage()+"---登陸失敗");
		response.setHeader("content-type","text/html;charset=UTF-8");
		response.getWriter().println("<script>alert('"+ authentication.getMessage()+"');</script>");

	}

}

一樣的在SecurityConfig中配置失敗處理器,再次登陸:ide

    能夠看到打印出的異常信息爲「壞的憑證」,實際上這個是Security中默認的異常信息,咱們跑一遍源碼,來看一看Security是怎麼對比咱們在表單輸入的信息與UserDetailServer中(數據庫)的對比,以及異常的處理的。

    任意輸入用戶名,密碼,點擊登陸,咱們仍是先來到了UsernamePasswordAuthenticationFilter中。

咱們繼續往下走,一直走到咱們的UserDetailServer的實現中。

    走到User的時候咱們直接走進去,進入到DaoAuthenticationProvider,在這裏會對User進行初步的檢查,咱們看右上角的堆棧信息,能夠看到loadedUser中我畫紅框值爲true的屬性,實際上這幾個是框架默認填充的值,這由於咱們只調用了三個參數的構造器,若是咱們調用七個參數的構造器,就能夠根據咱們本身的業務邏輯去進行true或false的判斷,拋出相應的異常信息。

當咱們繼續走,下面就開始對User進行用戶名,密碼,是否可用等等各類檢查,若是發現出現問題,則拋出異常信息。

因爲我填寫的密碼是錯誤的,因此在檢查過程當中,拋出如下異常「壞的憑證」,認證是是失敗的,那個false的含義是我是第一次通過認證的。

而這裏拋出的異常信息「壞的憑證」則會被咱們的失敗處理器所捕獲,這就是異常信息捕獲的所有過程。

3、自定義異常信息

    第二節咱們詳細的講解了異常信息的捕獲流程,可是在咱們的實際業務需求中,異常信息可能不是「壞的憑證」這樣的字符串,若是我想自定義信息,怎麼辦呢?也很簡單,請看代碼:

    我將UserDetailServer稍做修改。

import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

@Component
public class MyUserDetailsServer implements UserDetailsService {

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// TODO Auto-generated method stub
		if("admin".equals(username)){
			
			throw new RuntimeException("admin禁止登陸");
		}
		return new User(username, "$2a$10$ofPkBDUezOJp6Sik63Q/0.QlU8a1itEyzldjSXqfn2nDPqXjN0Ljm", AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
	}

}

我這裏只是舉一個例子,具體大家的業務需求是怎樣的,本身實現就好。重啓項目,使用admin登陸,效果以下。

相關文章
相關標籤/搜索