spring-security 個性化用戶認證流程——自定義登陸頁面(可配置)

1.定義本身的登陸頁面
咱們須要根據本身的業務系統構建本身的登陸頁面以及登陸成功、失敗處理
在spring security提供給個人登陸頁面中,只有用戶名、密碼框,而自帶的登陸成功頁面是空白頁面(能夠重定向以前請求的路徑中),而登陸失敗時也只是提示用戶被鎖定、過時等信息。html

在實際的開發中,則須要更精細力度的登陸控制,記錄錯誤的日誌(錯誤的次數等)spring

2.自定義登陸頁面json

  • 配置登陸頁面的路徑
    BrowserSecurityConfig類中配置登陸頁面的路徑
    http.formLogin()  
        .loginPage("/sign.html")   //位於resources/resources/sign.html
        .and()
        .authorizeRequests()
        .anyRequest().authenticated();

    頁面內容以下:瀏覽器

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>sign.html</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>

啓動以後,訪問咱們的路徑:http://localhost:8080/sign.html
spring-security 個性化用戶認證流程——自定義登陸頁面(可配置)
這個時候瀏覽器會報錯:重定向的次數過多,這是爲何呢?
由於在配置中,咱們只是配置了loginPage("/sign.html"),可是又沒有給該請求作受權,又由於沒有作受權,又被跳轉給sign.html頁面,因此會是:重定向的次數過多。
此時:須要再配置受權路徑,改造以後緩存

http.formLogin()  
        .loginPage("/sign.html")  
        .and()
        .authorizeRequests()
        .antMatchers("/sign.html").permitAll()  //當訪問sign.html這個頁面的時候不須要進行身份認證
        .anyRequest().authenticated();

在sign.html中,本身配置了一個post路徑,在spring security原理中,表單登陸其實是由UsernamePasswordAuthenticationFilter這個過濾器來處理的,在這個過濾器中spring-security 個性化用戶認證流程——自定義登陸頁面(可配置)
處理的是/login 請求,爲了讓UsernamePasswordAuthenticationFilter這個過濾器知道處理咱們自定義的登陸路徑/authentication/form,還須要再配置登陸的處理請求安全

http.formLogin()  
        .loginPage("/sign.html")  
        .loginProcessingUrl("/authentication/form") //登陸請求
        .and()
        .authorizeRequests()
        .antMatchers("/sign.html").permitAll() 
        .anyRequest().authenticated();

啓動以後,繼續訪問咱們的路徑:http://localhost:8080/sign.html
spring-security 個性化用戶認證流程——自定義登陸頁面(可配置)
輸入帳戶名和密碼,登陸以後會報錯,403app

spring-security 個性化用戶認證流程——自定義登陸頁面(可配置)

在默認狀況下,spring security提供了跨站請求僞造的防禦,用CSRF Token來完成的,在***和防禦的時候再細講,目前先把跨站請求僞造的功能先disable掉。ide

http.formLogin()  
        .loginPage("/sign.html")  
        .loginProcessingUrl("/authentication/form") //登陸請求
        .and()
        .authorizeRequests()
        .antMatchers("/sign.html").permitAll() 
        .anyRequest().authenticated()
        .and()
        .csrf().disable();

啓動以後,繼續訪問咱們的路徑:http://localhost:8080/user/1 ,系統會幫咱們重定向到sign.html頁面
此時咱們輸入正確的用戶名和密碼就能夠訪問咱們的請求了
spring-security 個性化用戶認證流程——自定義登陸頁面(可配置)post

3.優化rest請求和html請求
完成了基本功能以後還須要繼續優化咱們的代碼結構,是要面向可重用的一種。
目前有2個問題:優化

  • 發送的請求,例如:localhost:8080/user/1 須要身份認證的話返回HTML是不合理的,rest服務應該返回json
    想要作到的效果,若是是html請求則返回登陸頁上,若是不是則返回json數據 帶未受權(401狀態碼)
  • 咱們寫了一個標準的登陸頁面,可是咱們的目標是提供可重用的安全模塊,這個時候就須要提供可配置項
    (由於會有多個項目使用該模塊,可是多個項目它有不一樣的登陸模塊)
    流程以下:

spring-security 個性化用戶認證流程——自定義登陸頁面(可配置)

當咱們接收到html請求或者數據請求的時候,先判斷是否須要身份認證(spring security來作的)若是是否的話就直接返回了,若是是的話則須要跳轉到咱們自定義的Controller上面去(目前咱們的作法是跳轉到了sign.html頁面上)在該方法內判斷是html請求仍是數據請求。

Controller

@RestController
public class BrowserSecurityController {
    private Logger logger = LoggerFactory.getLogger(BrowserSecurityConfig.class);

    //拿到引起跳轉的請求(HttpSessionRequestCache把當前的請求緩存到Session中)
    private RequestCache requestCache = new HttpSessionRequestCache();

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Autowired
    private SecurityProperties securityProperties;

    //當須要身份認證時,跳轉到這裏
    @RequestMapping("/authentication/require")
    @ResponseStatus(code=HttpStatus.UNAUTHORIZED) //不是html請求時,返回401狀態碼
    public SimpleResponse requireAuthentication(HttpServletRequest request,HttpServletResponse response) throws IOException {
        //以前緩存的請求(能夠拿到引起跳轉的請求)
        SavedRequest savedRequest = requestCache.getRequest(request, response);
        if (savedRequest != null) {
            String targetUrl = savedRequest.getRedirectUrl();
            logger.info("引起跳轉的請求是:"+targetUrl);
            //是否以.html結尾,若是是則跳轉到登陸頁面
            if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) {
                //這個url,咱們須要作成可配置的url(由於咱們不可能每次都跳轉到咱們本身的寫的固定登陸頁面,須要根據每一個項目的不一樣)
                //這個時候就須要用到**Properties 配置文件類來作靈活性配置
                redirectStrategy.sendRedirect(request, response, securityProperties.getBrowser().getLoginPage());
            }
            //若是不是html請求,則返回401狀態碼以及錯誤信息
        }
        return new SimpleResponse("訪問的服務須要身份認證,請引導用戶到登陸頁");
    }
}

SecurityProperties自定義的登陸頁配置屬性類,爲了可配置化

#另外的項目的登陸請求的頁面
core.security.browser.loginPage = /demo-sign.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>demo-sign</title>
</head>
<body>
    <h2>demo-sign自定義登陸頁</h2>
</body>
</html>

而咱們不想單純的要一個簡單的配置是,而是可管理的配置類,由於後面會有其餘的配置,例如驗證碼的配置,OAuth的配置,等 這個時候須要同一個的配置類入口(SecurityProperties

spring-security 個性化用戶認證流程——自定義登陸頁面(可配置)

//讀取配置文件內的信息
@ConfigurationProperties(prefix="core.security")
public class SecurityProperties {
    private BrowserProperties browser = new BrowserProperties();

    public BrowserProperties getBrowser() {
        return browser;
    }
    public void setBrowser(BrowserProperties browser) {
        this.browser = browser;
    }
}

public class BrowserProperties {
    //標準的登陸頁面,若是其餘項目沒有配置則使用默認的登陸配置
    private String loginPage = "/sign.html";

    public String getLoginPage() {
        return loginPage;
    }
    public void setLoginPage(String loginPage) {
        this.loginPage = loginPage;
    }
}

//爲了使core.security生效則須要一個@Configuration類
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)
public class SecurityCoreConfig {
}

//最後要在權限配置類**BrowserSecurityConfig**中 配置放行的url
  private final static String loginPage = "/authentication/require";
    @Autowired
    private SecurityProperties securityProperties;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()  
        .loginPage(loginPage)
        .loginProcessingUrl("/authentication/form")
        .and()
        .authorizeRequests()
        .antMatchers(loginPage).permitAll()
        //自定義的登陸頁面權限放開
        .antMatchers(securityProperties.getBrowser().getLoginPage()).permitAll()
        .anyRequest().authenticated()
        .and()
        .csrf().disable();
    }

第一種狀況:訪問請求:http://localhost:8080/user/1
spring-security 個性化用戶認證流程——自定義登陸頁面(可配置)

第二種狀況:訪問請求:http://localhost:8080/index.html
spring-security 個性化用戶認證流程——自定義登陸頁面(可配置)

第三種狀況:關閉配置,繼續訪問請求:http://localhost:8080/index.html

#core.security.browser.loginPage = /demo-sign.html

spring-security 個性化用戶認證流程——自定義登陸頁面(可配置)

這個功能就是咱們目前想要的,能夠針對不一樣的請求對於沒有權限時的攔截以及調整判斷。

相關文章
相關標籤/搜索