Spring Security認證配置(二)


學習本章之前,可以先了解下上篇Spring Security基本配置

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

1、訪問調用者服務時,如果是html請求,則跳轉到登錄頁,否則返回401狀態碼和錯誤信息

2、調用方可自定義登錄頁面。如果沒有配置,則使用認證中心的標准登錄頁

對於第一點,可以畫個圖:

接下來看具體的配置:

 

spring-security-browser

先建一個認證中需要用到的常量類:

/**
 * Security相關常量類
 */
public class SecurityConst {

    /** 默認登錄頁url */
    public static final String AUTH_REQUIRE = "/authentication/require";
    
    /** 登錄頁請求url */
    public static final String AUTH_FORM = "/authentication/form";

}

在src/main/resources下再建立一個resources目錄,用來放靜態文件。然后在resources下建立login.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>

建立配置類(方便服務調用者自定義配置):

/**
 * security相關配置(不能取名SecurityProperties,因為security中也有這個類名,不然會報錯)
 */
@Getter
@Setter
@ConfigurationProperties(prefix = "security")
public class SecurityProperty {

    private BrowserProperty browser = new BrowserProperty();

}
/**
 * security-瀏覽器相關配置
 */
@Getter
@Setter
public class BrowserProperty {

    private String loginPage = "/login.html"; // 登錄頁  

}

修改下SecurityConfig類中的配置:

   @Autowired
    private SecurityProperty securityProperty;

    @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
            .and()
            .authorizeRequests() // 對請求授權
            .antMatchers(SecurityConst.AUTH_REQUIRE, securityProperty.getBrowser().getLoginPage()).permitAll() // 允許所有人訪問login.html和自定義的登錄頁
            .anyRequest() // 任何請求
            .authenticated()// 需要身份認證
            .and()
            .csrf().disable() // 關閉跨站偽造
        ;
    }

配置代碼分析:

從上面可以看出,當第一次請求時(如http://localhost:18081/user),會先跳轉到loginPage配置的路徑里,即/authentication/require

/authentication/require/login.html這兩個請求不需要認證授權(第二個url是登錄頁,可以在調用方自定義配置的)

接下來,建立一個Controller,用來處理/authentication/require請求:

@Slf4j
@RestController
public class SecurityController {

    private RequestCache requestCache = new HttpSessionRequestCache(); // 請求緩存

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();// 頁面跳轉

    @Autowired
    private SecurityProperty securityProperty;

    /**
     * 當需要身份認證時,跳轉到這里 (如果是html請求,則跳轉到登錄頁,否則返回401狀態碼和錯誤信息)
     */
    @SneakyThrows
    @RequestMapping(SecurityConst.AUTH_REQUIRE)
    @ResponseStatus(code = HttpStatus.UNAUTHORIZED) // 未授權狀態碼401
    public SimpleResponse requireAuthentication(HttpServletRequest request, HttpServletResponse response) {
        // 從session中取之前緩存的請求
        SavedRequest savedRequest = requestCache.getRequest(request, response);
        if (savedRequest != null) {
            String targetUrl = savedRequest.getRedirectUrl();
            log.info("引發跳轉的請求是:" + targetUrl);
            if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) {
                // 跳轉到指定的頁面
                redirectStrategy.sendRedirect(request, response, securityProperty.getBrowser().getLoginPage());
            }
        }
        return new SimpleResponse("訪問的服務需要身份認證,請引導用戶到登錄頁");
    }

}
/**
 * 響應
 */
@Getter
@Setter
@AllArgsConstructor
public class SimpleResponse {

    private Object content;

}

RequestCache接口聲明了緩存與恢復操作。默認實現類是HttpSessionRequestCache,接口的聲明如下:

public interface RequestCache {
 
 // 將request緩存到session中
void saveRequest(HttpServletRequest request, HttpServletResponse response);
 
 // 從session中取request
 SavedRequest getRequest(HttpServletRequest request, HttpServletResponse response);
 
 // 獲得與當前request匹配的緩存,並將匹配的request從session中刪除
HttpServletRequest getMatchingRequest(HttpServletRequest request,
 HttpServletResponse response);
 
 // 刪除緩存的request
 void removeRequest(HttpServletRequest request, HttpServletResponse response);
}

對request的緩存,可參考Spring Security 源碼解析(一)

 

建立好之后的文件目錄如下所示:

 

spring-security-demo

在src/main/resources下再建立一個resources目錄,用來放靜態文件。然后在resources下建立plogin.html頁面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>登錄</title>
</head>
<body>
    <h2>自定義登錄頁面</h2>
</body>
</html>

 

啟動服務,訪問 http://localhost:18081/user,跳轉到如下頁面:

可以看到,訪問/user時,需要授權認證,然后跳轉到/authentication/require,直接返回401狀態碼和我們自定義的content數據

 

 訪問 http://localhost:18081/index.html,跳轉到如下頁面:

可以看到,訪問 /index.html 時,需要授權認證,然后跳轉到 /authentication/require,發現是html請求,重定向到 login.html 頁面

 

接下面,在服務調用者的配置文件application.yml中,加上自定義的登錄頁配置:

security:
  browser: 
    loginPage: /plogin.html

然后重啟項目,訪問http://localhost:18081/index.html,跳轉到如下頁面:

可以看到,現在跳轉到了自定義的登錄頁面

 

 


免責聲明!

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



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