事情是这样的,在学习Spring Security框架时,使用框架默认的登录页面,输入正确的账号密码后可以正常登录,但是将登录页面改为自定义页面后,就无法登录了。 如下:
密码账户密码肯定时没有问题的,看配置源码如下:
- 定制表格
<form action="/index" method="post" class="form">
Username: <input type="text" name="username"><br>
Password: <input type="password" name="password"><br>
<button type="submit">提交</button>
</form>
- 实现安全配置类
@Configuration
public class SecurityConfig2 extends WebSecurityConfigurerAdapter {
//内存存储用户和密码,模拟数据库查数据
@Bean
public UserDetailsService userDetailsService(){
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("admin").password(encoder().encode("123")).authorities("role").build());
return manager;
}
/** * 配置拦截机制 * @param http * @throws Exception */
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//所有地址均开启登录认证
.authorizeRequests()
.anyRequest().authenticated()
.and()
//开启表单认证
.formLogin()
//配置登录页面,无该配置会使用框架自带页面
.loginPage("/static/login.html")
//设置登录成功跳转资源地址
.defaultSuccessUrl("/index")
//登录失败地址
.failureUrl("/static/login.html")
.permitAll()
.and()
//禁用 CSRF 防御功能
.csrf().disable();
;
}
//密码加密工具类
@Bean(name = "passwordEncoder")
PasswordEncoder encoder(){
return new BCryptPasswordEncoder();
}
}
输入正确的账号和密码后,如上图所示,无法进行正常跳转。首先排除用户名密码错误的问题,因为使用devtool工具,返回的状态码为302,资源已被拦截,如下:
回顾登录逻辑,输入任何地址都会跳转到/static/login.html
页面,进行登录验证。输入用户名和密码后,表单将提交到/index
,并返回该页面的内容。
问题就出现在这里,跳转到登录页面没错,但是会话没有被记录呀,在之前的默认登陆页面,会话是默认记录的。而_小许_是直接提交到/index
下,会话没有被记录,因此index被拦截由返回到登录页面,这里陷入了四循环,就出现了文章开头的一幕。那么如何解决该问题呢?
记录会话状态
Spring Security框架自动实现了会话状态的记录,不需要开发者自定义实现。只需要以接口的形式调用即可。
loginProcessingUrl
是会话状态的代理接口,在配置HttpSecurity
时将登录的数据转发到该接口即可,地址也是由开发者自行定义。如下:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/static/login.html")
//会话状态代理接口
.loginProcessingUrl("/doLogin")
.defaultSuccessUrl("/index")
.failureUrl("/static/login.html")
.permitAll()
.and()
.csrf().disable();
}
<form action="/doLogin" method="post" class="form">
Username: <input type="text" name="username"><br>
Password: <input type="password" name="password"><br>
<button type="submit">提交</button>
</form>
表单的认证地址为doLogin地址,安全框架的会话代理接口为doLogin,因此框架实现了会话状态的记录。
经过此配置后就可以访问了。有时访问的路径不对还会出现404,可以通过successForwardUrl
强制转到配置的主页面。
配置登录成功跳转目录的方法由两个
defaultSuccessUrl
和successForwardUrl
,它们的区别是前者在访问的是否为参数配置的页面进行跳转。例如,在访问 http://localhost:8080/你好时,defaultSuccessUrl配置额index,那么将会返回到hello,uri的优先级高;successForwardUrl无论地址栏输入的是什么都会返回配置的参数的资源。
还有一些问题需要注意:
- 表单提交和页面跳转成功必须是post请求;
- 表单提交必须转到
loginProcessingUrl
,否则会返回302; loginPage
方法配置自定义页面,也可以通过控制器返回页面;- 关闭
.csrf().disable()
。
第四个小徐还没看懂,但是我尝试了一下,注释掉代码后确实报了302的错误。我学习后会更新的。