Spring Security(四):個性化用戶認證流程

第三章已經可以從數據庫查出密碼進行各種校驗了,但是對於各種登錄認證流程來說還是單調,無法滿足我們的企業級開發需求,本篇就進行一個個性化用戶認證流程處理,包括自定義登錄頁面,自定義登錄成功處理,自定義登陸失敗處理。

自定義登錄頁面

自定義的登錄頁:meicloud-signIn.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登錄</title>
</head>
<body>
	<h2>標準登錄頁面</h2>
	<h3>表單登錄</h3>
	<form action="/authentication/form" method="post">
		<table>
			<tr>
				<td>用戶名:</td> 
				<td><input type="text" name="username"></td>
			</tr>
			<tr>
				<td>密碼:</td>
				<td><input type="password" name="password"></td>
			</tr>
			<tr>
				<td colspan="2"><button type="submit">登錄</button></td>
			</tr>
		</table>
	</form>
</body>
</html>

配置自定義登錄頁

  • 在我們前面篇章講到的 BrowserSecurityConfig 配置類中進行配置,如下 .loginPage()配置項
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.formLogin()
				// 使用自定義的表單登錄頁面
				.loginPage("/meicloud-signIn.html")
				// 以下這行 UsernamePasswordAuthenticationFilter 會知道要處理表單的 /authentication/form 請求,而不是默認的 /login
				.loginProcessingUrl("/authentication/form")
				.and()
				.authorizeRequests()
				// 排除對 "/meicloud-signIn.html" 的身份驗證
				.antMatchers("/meicloud-signIn.html").permitAll()
				// 表示所有請求都需要身份驗證
				.anyRequest()
				.authenticated()
				.and()
				.csrf().disable();// 暫時把跨站請求僞造的功能關閉掉
	}
  • .loginProcessingUr()表示要處理表單的 /authentication/form 登錄請求,而不是默認的 /login
  • 要注意的是,.anyRequest表示所有請求都需要身份驗證,導致我們的登錄頁/meicloud-signIn.html也需要進行身份驗證,所以我們需要配置.antMatchers("/meicloud-signIn.html").permitAll()來使得登錄頁不需要進行攔截認證。

自定義登錄成功處理

實現AuthenticationSuccessHandler接口,實現onAuthenticationSuccess()方法

  • 但是一般情況下不會去直接實現該接口,一般可以繼承該接口的實現類,如下,這樣使得給到前端的請求有更多種選擇,比如JSON或者是跳到另一個路徑。
@Component("meicloudAuthenticationSuccessHandler")
public class MeicloudAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

	private Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	private ObjectMapper objectMapper;
	@Autowired
	private SecurityProperties securityProperties;
	private RequestCache requestCache = new HttpSessionRequestCache();

	/**
	 * 登錄成功處理
	 * @param authentication 封裝認證信息,包括認證請求信息,ip、session信息等,還包括認證通過以後,自定義的UserDetailService返回的UserDetails信息
	 */
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		logger.info("登錄成功");

		if (LoginResponseType.JSON.equals(securityProperties.getBrowser().getSignInResponseType())) {
			response.setContentType("application/json;charset=UTF-8");
			String type = authentication.getClass().getSimpleName();
			response.getWriter().write(objectMapper.writeValueAsString(new SimpleResponse(type)));
		} else {
			// 如果設置了meicloud.security.browser.singInSuccessUrl,總是跳到設置的地址上
			// 如果沒設置,則嘗試跳轉到登錄之前訪問的地址上,如果登錄前訪問地址爲空,則跳到網站根路徑上
			if (StringUtils.isNotBlank(securityProperties.getBrowser().getSingInSuccessUrl())) {
				requestCache.removeRequest(request, response);
				setAlwaysUseDefaultTargetUrl(true);
				setDefaultTargetUrl(securityProperties.getBrowser().getSingInSuccessUrl());
			}
			super.onAuthenticationSuccess(request, response, authentication);
		}
	}
}
  • 然後需要在 BrowserSecurityConfig 配置類中進行配置,加上一行 .successHandler() 配置
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.formLogin()
				.loginPage("/meicloud-signIn.html")
				.loginProcessingUrl("/authentication/form")
				// 配置成功處理
				.successHandler(meicloudAuthenticationSuccessHandler)
				.and()
				.authorizeRequests()
				.antMatchers("/meicloud-signIn.html").permitAll()
				.anyRequest()
				.authenticated()
				.and()
				.csrf().disable();
	}

自定義登陸失敗處理

和登錄成功處理類似,實現 AuthenticationFailHandler 接口,實現onAuthenticationFailure()方法

  • 同理一樣不會去直接實現該接口,可以繼承它的實現類 SimpleUrlAuthenticationFailureHandler
 @Component("meicloudAuthenctiationFailureHandler")
class MeicloudAuthencationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private SecurityProperties securityProperties;

    /**
     * 登錄失敗處理
     * @param exception 包含了登錄錯誤時的異常,包括用戶名沒找着、密碼不正確等等
     */
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {

        logger.info("登錄失敗");

        if (LoginResponseType.JSON.equals(securityProperties.getBrowser().getSignInResponseType())) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(new SimpleResponse(exception.getMessage())));
        }else{
            super.onAuthenticationFailure(request, response, exception);
        }

    }
}
  • 同樣需要添加在 BrowserSecurityConfig 中添加 .failureHandler() 配置
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.formLogin()
				.loginPage("/meicloud-signIn.html")
				.loginProcessingUrl("/authentication/form")
				// 配置成功處理
				.successHandler(meicloudAuthenticationSuccessHandler)
				.failureHandler(meicloudAuthenticationFailureHandler)
				.and()
				.authorizeRequests()
				.antMatchers("/meicloud-signIn.html").permitAll()
				.anyRequest()
				.authenticated()
				.and()
				.csrf().disable();
	}

總結

需求 實現
自定義登錄頁面 http.formLogin().loginPage("/meicloud-signIn.html")
自定義登錄成功處理 AuthenticationSuccessHandler
自定義登錄失敗處理 AuthenticationFailureHandler

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章