系列博文
项目已上传至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(); } }