前面我们简单使用了 Spring Security Spring Security初使用
我们使用的是默认的登录页面,这个登录页面我们是可以自定义的。
接下来我们继续完善前面的 SecurityConfig 类,继续重写它的 configure(WebSecurity web) 和 configure(HttpSecurity http) 方法
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()//定义用户
.withUser("zhangsan")//用户名
.password("zhangsan123")//密码
.roles("admin");//用户角色
//如果需要配置多个用户,用 and 相连
}
@Override
public void configure(WebSecurity web) throws Exception {
//用来配置忽略掉的 URL 地址,一般对于静态文件,我们可以采用此操作。
web.ignoring().antMatchers("/js/**", "/css/**", "/images/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()//结束当前标签,上下文回到HttpSecurity,开启新一轮的配置。
.formLogin()
.loginPage("/login.html")//登录页
.permitAll()//登录相关的页面/接口不拦截。
.and()
.csrf().disable();//关闭csrf
}
}
在resources下创建static,然后在static目录下创建登录页面login.html
<html lang="en">
<head>
<meta charset="utf-8">
<title>登录title>
head>
<body>
<div>
<form action="/login.html" method="post">
<div class="input">
<label for="name">用户名label>
<input type="text" name="username" id="name">
div>
<div class="input">
<label for="pass">密码label>
<input type="password" name="password" id="pass">
div>
<div class="button login">
<button type="submit">登录button>
div>
form>
div>
body>
html>
这里没写样式,就简单演示一下
然后启动项目访问http://localhost:8080/hello,可以看到会重定向到http://localhost:8080/login.html
然后输入配置的用户名密码即可登录成功。
在 Spring Security 中,如果我们不做任何配置,默认的登录页面和登录接口的地址都是 /login,
GET 请求表示你想访问登录页面,如果是 POST 请求,表示你想提交登录数据。
当我们配置了 loginPage 为 /login.html 之后,就是设置登录页面和登录接口的地址为 /login.html。
如果想把登录页面和登录接口地址分开可以通过 loginProcessingUrl 方法来指定登录接口地址。
.and()
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/doLogin")
.permitAll()
.and()
然后修改login.html中form标签action值为/doLogin就可以登录成功。
form 表单的相关配置在 FormLoginConfigurer 中,该类继承自 AbstractAuthenticationFilterConfigurer,
在 AbstractAuthenticationFilterConfigurer 的构造方法中,有如下代码:
这里配置默认的 loginPage 为 /login
FormLoginConfigurer 的初始化方法 init 方法中也调用了父类的 init 方法:
而在父类的 init 方法中,又调用了 updateAuthenticationDefaults
可以看到,如果用户没有给 loginProcessingUrl 设置值的话,默认就使用 loginPage 作为 loginProcessingUrl。
所以这也是如果没配置两个配置地址是一样的原因。
登录表单中的参数是 username 和 password,我们可以回到 FormLoginConfigurer 类中,在它的构造方法中,我们可以看到有两个配置用户名密码的方法:
在这里,首先 super 调用了父类的构造方法,传入了 UsernamePasswordAuthenticationFilter 实例,该实例将被赋值给父类的 authFilter 属性。
接下来 usernameParameter 方法如下:
getAuthenticationFilter 实际上是父类的方法,在这个方法中返回了 authFilter 属性,也就是一开始设置的 UsernamePasswordAuthenticationFilter 实例,然后调用该实例的 setUsernameParameter 方法去设置登录用户名的参数:
当登录请求从浏览器来到服务端之后,我们要从请求的 HttpServletRequest 中取出来用户的登录用户名和登录密码,在 UsernamePasswordAuthenticationFilter 类中,有如下两个方法:
可以看到,这个时候,就用到默认配置的 username 和 password 了。
这两个参数我们也可以自己配置,配置方式如下:
.and()
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/doLogin")
.usernameParameter("name")
.passwordParameter("passwd")
.permitAll()
.and()
配置完成后,也要修改一下前端页面的name参数名,配置完成后,重启进行登录测试。
登录后我们要进行回调
登录成功重定向 URL 相关的方法有两个:
相关配置如下:
.and()
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/doLogin")
.usernameParameter("name")
.passwordParameter("passwd")
.defaultSuccessUrl("/index")
.successForwardUrl("/index")
.permitAll()
.and()
「注意:实际操作中,defaultSuccessUrl 和 successForwardUrl 只需要配置一个即可。」
与登录成功相似,登录失败也是有两个方法:
「这两个方法在设置的时候也是设置一个即可」
。注销登录的默认接口是 /logout
.and()
.logout()
.logoutUrl("/logout")
.logoutRequestMatcher(new AntPathRequestMatcher("/logout","POST"))
.logoutSuccessUrl("/index")
.deleteCookies()
.clearAuthentication(true)
.invalidateHttpSession(true)
.permitAll()
.and()
好了,这章到这里就结束了。