系列博文
項目已上傳至guthub 傳送門
JavaWeb-SpringSecurity初認識 傳送門
JavaWeb-SpringSecurity在數據庫中查詢登陸用戶 傳送門
JavaWeb-SpringSecurity自定義登陸頁面 傳送門
JavaWeb-SpringSecurity實現需求-判斷請求是否以html結尾 傳送門
JavaWeb-SpringSecurity自定義登陸配置 傳送門
JavaWeb-SpringSecurity圖片驗證ImageCode 傳送門
JavaWeb-SpringSecurity記住我功能 傳送門
JavaWeb-SpringSecurity使用短信驗證碼登陸 傳送門
在static文件夾下添加一個login.html,作為自定義登陸頁面

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <h1>Gary登陸頁面</h1> <form action="/loginPage" method="post"> 用戶名: <input type="text" name="username"> <br> 密碼: <input type="password" name="password"> <br> <input type="submit"> </form> </body> </html>
在SecurityConfig.java中的configure()方法中配置表單校驗,添加一個自定義跳轉的頁面路徑/login.html
protected void configure(HttpSecurity http) throws Exception{ //表單驗證(身份認證) http.formLogin() //自定義登陸頁面 .loginPage("/login.html") .and() //請求授權 .authorizeRequests() //所有請求都被攔截,跳轉到(/login請求中) .anyRequest() //都需要我們身份認證 .authenticated(); }
運行程序,發現頁面進入死循環,提示錯誤頁面包含的重定義過多了
原因:用戶想要進入我們自定義的登陸頁面,需要SpringSecurity進行身份認證->但用戶要通過SpringSecurity,就會跳轉到我們自定義的登陸頁面->用戶進入我們自定義的登陸頁面,就需要SpringSecurity進行身份認證...
無限死循環了!!!

package com.Gary.GaryRESTful.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; //Web應用安全適配器 @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter{ //告訴SpringSecurity密碼用什么加密的 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } protected void configure(HttpSecurity http) throws Exception{ //表單驗證(身份認證) http.formLogin() //自定義登陸頁面 .loginPage("/login.html") .and() //請求授權 .authorizeRequests() //所有請求都被攔截,跳轉到(/login請求中) .anyRequest() //都需要我們身份認證 .authenticated(); } }
所以我們在配置SecurityConfig.java中的configure()時,對路徑/login.html進行請求放行
protected void configure(HttpSecurity http) throws Exception{ //表單驗證(身份認證) http.formLogin() //自定義登陸頁面 .loginPage("/login.html") .and() //請求授權 .authorizeRequests() //在訪問我們的URL時,我們是不需要省份認證,可以立即訪問 .antMatchers("/login.html").permitAll() //所有請求都被攔截,跳轉到(/login請求中) .anyRequest() //都需要我們身份認證 .authenticated(); }
此時,我們再訪問login.html時,發現就可以進入到我們自定義的登陸頁面了

package com.Gary.GaryRESTful.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; //Web應用安全適配器 @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter{ //告訴SpringSecurity密碼用什么加密的 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } protected void configure(HttpSecurity http) throws Exception{ //表單驗證(身份認證) http.formLogin() //自定義登陸頁面 .loginPage("/login.html") .and() //請求授權 .authorizeRequests() //在訪問我們的URL時,我們是不需要省份認證,可以立即訪問 .antMatchers("/login.html").permitAll() //所有請求都被攔截,跳轉到(/login請求中) .anyRequest() //都需要我們身份認證 .authenticated(); } }
此時,我們在自己的頁面中輸入數據庫中賬號密碼,頁面的攔截器都不會生效
這是因為login.html中表單/loginPage請求路徑攔截器不認識
按住Ctrl+Shift+T,可以找到SpringSecurity攔截器中UsernamePasswordAuthenticationFilter的方法
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter { // ~ Static fields/initializers // ===================================================================================== public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username"; public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password"; private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY; private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY; private boolean postOnly = true; // ~ Constructors // =================================================================================================== public UsernamePasswordAuthenticationFilter() { super(new AntPathRequestMatcher("/login", "POST")); }
現在需要我們login.html中的表單發送請求訪問SpringSecurity攔截器中的UsernamePasswordAuthenticationFilter()這個方法,處理用戶登陸的請求
(如果要使用UsernamePasswordAuthenticationFilter()這個方法處理用戶登陸,一定需要在配置表單登陸時,添加一個csrf跨站請求偽造的防護)
protected void configure(HttpSecurity http) throws Exception{ //表單驗證(身份認證) http.formLogin() //自定義登陸頁面 .loginPage("/login.html") //如果URL為loginPage,則用SpringSecurity中自帶的過濾器去處理該請求 .loginProcessingUrl("/loginPage") .and() //請求授權 .authorizeRequests() //在訪問我們的URL時,我們是不需要省份認證,可以立即訪問 .antMatchers("/login.html").permitAll() //所有請求都被攔截,跳轉到(/login請求中) .anyRequest() //都需要我們身份認證 .authenticated() //SpringSecurity保護機制 .and().csrf().disable(); }

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <h1>Gary登陸頁面</h1> <form action="/loginPage" method="post"> 用戶名: <input type="text" name="username"> <br> 密碼: <input type="password" name="password"> <br> <input type="submit"> </form> </body> </html>

package com.Gary.GaryRESTful.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; //Web應用安全適配器 @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter{ //告訴SpringSecurity密碼用什么加密的 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } protected void configure(HttpSecurity http) throws Exception{ //表單驗證(身份認證) http.formLogin() //自定義登陸頁面 .loginPage("/login.html") //如果URL為loginPage,則用SpringSecurity中自帶的過濾器去處理該請求 .loginProcessingUrl("/loginPage") .and() //請求授權 .authorizeRequests() //在訪問我們的URL時,我們是不需要省份認證,可以立即訪問 .antMatchers("/login.html").permitAll() //所有請求都被攔截,跳轉到(/login請求中) .anyRequest() //都需要我們身份認證 .authenticated() //SpringSecurity保護機制 .and().csrf().disable(); } }