Spring Security是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入spring boot-starter-security模块,进行少量的配置,即可实现强大的安全管理!
记住几个类:
-
WebSecurityConfigurerAdapter: 自定义Security策略
-
AuthenticationManagerBuilder: 自定义认证策略
-
@EnableWebSecurity:开启WebSecurity模式
Spring Security的两个主要目标是"认证"和"授权”(访问控制)
“认证”(Authentication) "授权”(Authorization)用户认证和授权
项目搭建
使用SpringBoot搭建一个简单的web项目
主要pom依赖
<!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--thymeleaf模板引擎-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
Controller层代码
@Controller
public class RouteController {
//访问路径为 / 或者 index 时返回我们的index页面
@RequestMapping({"/","index"})
public String index(){
return "index";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "views/login";
}
@RequestMapping("/level1/{id}")
public String level1(@PathVariable("id") int id){
return "views/level1/"+id;
}
@RequestMapping("/level2/{id}")
public String level2(@PathVariable("id") int id){
return "views/level2/"+id;
}
@RequestMapping("/level3/{id}")
public String level3(@PathVariable("id") int id){
return "views/level3/"+id;
}
}
编写SecurityConfig类
编写SecurityConfig继承WebSecurityConfigurerAdapter并加上 @EnableWebSecurity注解
WebSecurityConfigurerAdapter是security中浏览器登录设置的主类,继承后常用的重写方法:
HttpSecurity(HTTP请求安全处理)
AuthenticationManagerBuilder(身份验证管理生成器)
WebSecurity(WEB安全)
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
授权(HTTP请求安全处理)、开启登录页面
在 SecurityConfig 中 重写 HttpSecurity 方法
定义首页所有人都可以访问,功能页只有对应权限的人才可以访问,当用未登录时点击页面会跳转至登录页面
http.formLogin() 方法:开启登录页面
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//请求授权的规则
http.authorizeRequests()
.antMatchers("/").permitAll() //首页都可访问
.antMatchers("/level1/**").hasRole("vip1") //level1下的页面只有vip1才可以访问
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
//没有权限进入登录页面,需要开启登录页面
http.formLogin();
}
开启登录页面后若未登录,点击其他需要权限的页面时会进入security
默认的 /login 路径
主页面
认证(身份验证管理生成器)
在 SecurityConfig 中 重写 AuthenticationManagerBuilder 方法
使用inMemoryAuthentication() 方法自定义用户且赋予权限(这些数据可从数据库读取auth.jdbcAuthentication())
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("zhangsan").password("123456").roles("vip2","vip3")
.and()
.withUser("root").password("123456").roles("vip1","vip2","vip3")
.and()
.withUser("guest").password("123456").roles("vip1");
}
问题出现
当我们授权和认证结束后,启动项目会出现错误: java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
这是因为在SpringSecurity5+有了密码加密,只有对密码加密才可以正确登录
密码加密
passwordEncoder()方法
BCryptPasswordEncoder()是Security提供给我们多种加密方法的一种
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("zhangsan").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456") ).roles("vip1");
此时我们就可以登录,根据权限访问对应的页面
注销功能
Security为我们提供了默认的注销,只要开启注销功能且访问对应的 /logout 路径,它就会帮我们完成注销清除session
在重写的 HttpSecurity 方法中开启注销
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//请求授权的规则
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
//没有权限进入登录页面,需要开启登录页面
http.formLogin();
http.logout() //开启注销功能
.logoutSuccessUrl("/"); //成功注销后返回首页(默认返回登录)
}
在我们页面对应的注销标签路径上写入 /logout
<a class="item" th:href="@{/logout}">
i class="sign-out icon"></i> 注销
</a>
记住我
在重写的 HttpSecurity 方法中开启记住我,选择并登录后会将登陆的用户信息存入cookie
//开启记住我功能
http.rememberMe();