Spring Security認證配置(三)


學習本章之前,可以先了解下上篇Spring Security認證配置(二)

本篇想要達到這樣幾個目的:

1、登錄成功處理

2、登錄失敗處理

3、調用方自定義登錄后處理類型

 

具體配置代碼如下:

 

spring-security-browser

登錄成功處理:

/**
 * 自定義登錄成功后處理
 */
@Slf4j
@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {
        log.info("登錄成功...");

        response.setContentType("application/json;charset=UTF-8");
        // 返回authentication 認證信息
        response.getWriter().write(objectMapper.writeValueAsString(authentication));
    }

}

這段配置表示,登錄成功后,會向response中塞入authentication對象

代碼解析:

點開 AuthenticationSuccessHandler 類,可以看到里面只有一個onAuthenticationSuccess方法,如下:

onAuthenticationSuccess方法中,有個Authentication對象,其用法可參考AuthenticationManager、ProviderManager

 

登錄失敗處理:

/**
 * 自定義登錄失敗后處理
 */
@Slf4j
@Component
public class LoginFailureHandler implements AuthenticationFailureHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException exception) throws IOException, ServletException {
        log.info("登錄失敗");

        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); // 服務器內部異常500
        response.setContentType("application/json;charset=UTF-8");
        // 返回異常信息
        response.getWriter().write(objectMapper.writeValueAsString(exception));
    }

}

 這段配置表示,登錄失敗后,會向response中塞入AuthenticationException 對象,並返回500狀態碼

代碼解析:

AuthenticationFailureHandler 中也只有一個onAuthenticationFailure方法,其入參 AuthenticationException 是認證授權過程中拋出的異常類的基類,

 有以下幾個子類:

比較常用的是 BadCredentialsException(密碼錯誤)、UsernameNotFoundException(用戶名找不到)等等

 

修改下SecurityConfig類中的配置

  @Autowired
    private SecurityProperty securityProperty;
    
    @Autowired
    private LoginSuccessHandler loginSuccessHandler; //登錄成功處理
    
    @Autowired
    private LoginFailureHandler loginFailureHandler; //登錄失敗處理

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // formLogin()是默認的登錄表單頁,如果不配置 loginPage(url),則使用 spring security
        // 默認的登錄頁,如果配置了 loginPage()則使用自定義的登錄頁
        http.formLogin() // 表單登錄
            .loginPage(SecurityConst.AUTH_REQUIRE) 
            .loginProcessingUrl(SecurityConst.AUTH_FORM) // 登錄請求攔截的url,也就是form表單提交時指定的action
 .successHandler(loginSuccessHandler) .failureHandler(loginFailureHandler)
            .and()
            .authorizeRequests() // 對請求授權
            .antMatchers(SecurityConst.AUTH_REQUIRE, securityProperty.getBrowser().getLoginPage()).permitAll() // 允許所有人訪問login.html和自定義的登錄頁
            .anyRequest() // 任何請求
            .authenticated()// 需要身份認證
            .and()
            .csrf().disable() // 關閉跨站偽造
        ;
    }

 

啟動服務訪問 http://localhost:18081/index.html,跳轉到登錄頁,輸入正確的用戶名密碼(xwj/1234),跳轉到如下頁面:

查看控制台,可以看到Authentication對象包含的數據:

清掉瀏覽器緩存,然后再輸入錯誤的密碼,跳轉到如下頁面:

查看控制台,可以看到AuthenticationException對象包含的數據:

 

上面配置了登錄成功和失敗的處理,但是只能夠返回JSON格式的數據。如果希望返回一個頁面或者是跳轉,那就可以使用Security默認的處理方式

在Security中,默認的成功跟失敗處理分別是 SavedRequestAwareAuthenticationSuccessHandlerSimpleUrlAuthenticationFailureHandler

通過分析 AbstractAuthenticationProcessingFilter 類,可以看到:

在服務啟動時,如果在我們的配置類中,沒有配置這AuthenticationSuccessHandler跟AuthenticationFailureHandler,則使用這兩個默認的。如果配置了,則使用配置中

定義的登錄處理類。打個斷點可以看到:

 

修改下上面的配置代碼:

spring-security-browser

為了達到調用方自定義跳轉方式,增加配置類,如下:

/**
 * 登錄類型枚舉
 */
public enum LoginType {

    REDIRECT,

    JSON

}

修改BrowserProperty,增加默認的登錄類型(JSON):

@Getter
@Setter
public class BrowserProperty {

    private String loginPage = "/login.html"; // 登錄頁
    
    private LoginType loginType = LoginType.JSON; //登錄類型

}

接下來修改登錄與失敗處理類:

/**
 * 自定義登錄成功后處理
 * (繼承SavedRequestAwareAuthenticationSuccessHandler,這是默認的成功處理器,其帶有requestCache)
 */
@Slf4j
@Component
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired private SecurityProperty securityProperty;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {
        log.info("登錄成功...");

        if (LoginType.JSON.equals(securityProperty.getBrowser().getLoginType())) { // json請求(如ajax)
            response.setContentType("application/json;charset=UTF-8");
            // 返回authentication 認證信息
            response.getWriter().write(objectMapper.writeValueAsString(authentication));
        } else { // 跳轉
            super.onAuthenticationSuccess(request, response, authentication);
        }
    }

}
/**
 * 自定義登錄失敗后處理 
 * (繼承SimpleUrlAuthenticationFailureHandler,這是默認的失敗處理器)
 */
@Slf4j
@Component
public class LoginFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired private SecurityProperty securityProperty;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException exception) throws IOException, ServletException {
        log.info("登錄失敗");

        if (LoginType.JSON.equals(securityProperty.getBrowser().getLoginType())) { // json請求(如ajax)
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); // 服務器內部異常500
            response.setContentType("application/json;charset=UTF-8");
            // 返回異常信息
            response.getWriter().write(objectMapper.writeValueAsString(exception));
        } else {
            super.onAuthenticationFailure(request, response, exception);
        }
    }

}

spring-security-demo

在配置文件(application.yml)中,加上:

security:
  browser: 
    #loginPage: /plogin.html
    loginType: REDIRECT

 

重新啟動服務,訪問 http://localhost:18081/index.html,跳轉到登錄頁,輸入正確的用戶名密碼(xwj/1234),跳轉到具體的頁面:

清掉瀏覽器緩存,然后再輸入錯誤的密碼,跳轉到如下頁面:

從上面可以看到,返回401狀態碼,類型為Unauthorized,表示未認證。這里的????其實是認證失敗原因,打個斷點可以看到:

拋出了BadCredentialsException異常,"壞的憑證"表示密碼錯誤

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM