在第二章節,咱們主要學習了Security的自定義認證的實現和認證的流程,同時也存在一些問題,好比咱們想在用戶認證成功或失敗後記錄日誌等相關操做,咱們怎麼辦呢?別擔憂,Security已經爲咱們想好了,咱們只須要實現其提供的接口並配置便可。html
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
經過名字你們應該能夠猜出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的含義是我是第一次通過認證的。
而這裏拋出的異常信息「壞的憑證」則會被咱們的失敗處理器所捕獲,這就是異常信息捕獲的所有過程。
第二節咱們詳細的講解了異常信息的捕獲流程,可是在咱們的實際業務需求中,異常信息可能不是「壞的憑證」這樣的字符串,若是我想自定義信息,怎麼辦呢?也很簡單,請看代碼:
我將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登陸,效果以下。