一、配置Spring Security环境
- 新建工程:参考文章【Spring Boot】快速上手SpringBoot
- 导入Spring Security的依赖pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
我们还会用到Thymeleaf引擎:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
- 项目结构:
- 首页:index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div align="center">
<h1>首页</h1>
<table>
<tr>
<td>登录</td>
<td><a th:href="@{/to_login}">访问</a> </td>
<td>注销</td>
<td><a th:href="@{/logout}">访问</a></td>
</tr>
<tr>
<td>VIP1</td>
<td><a th:href="@{/vip1/1}">访问1</a> </td>
<td><a th:href="@{/vip1/2}">访问2</a> </td>
<td><a th:href="@{/vip1/3}">访问3</a> </td>
</tr>
<tr>
<td>VIP2</td>
<td><a th:href="@{/vip2/1}">访问1</a> </td>
<td><a th:href="@{/vip2/2}">访问2</a> </td>
<td><a th:href="@{/vip2/3}">访问3</a> </td>
</tr>
<tr>
<td>VIP3</td>
<td><a th:href="@{/vip3/1}">访问1</a> </td>
<td><a th:href="@{/vip3/2}">访问2</a> </td>
<td><a th:href="@{/vip3/3}">访问3</a> </td>
</tr>
</table>
</div>
</body>
</html>
- controller类:RouterController.java
@Controller
public class RouterController {
@RequestMapping({"/","/index"})
public String index(){
return "index";
}
@RequestMapping("/to_login")
public String login(){
return "views/login";
}
@RequestMapping("/vip1/{id}")
public String vip1(@PathVariable int id){
return "views/vip1/"+id;
}
@RequestMapping("/vip2/{id}")
public String vip2(@PathVariable int id){
return "views/vip2/"+id;
}
@RequestMapping("/vip3/{id}")
public String vip3(@PathVariable int id){
return "views/vip3/"+id;
}
}
- 页面:对应的VIP才可以访问其他页面,规定角色,我们需要用到Spring Security
二、Spring Security
官方解释:
Spring Security is a framework that provides authentication, authorization, and protection against common attacks. With first class support for both imperative and reactive applications, it is the de-facto standard for securing Spring-based applications.
Spring Security是一个提供身份验证、授权和针对常见攻击的保护的框架。它对命令式和反应式应用程序都提供了一流的支持,是保护基于spring的应用程序的事实标准。
官网地址:https://docs.spring.io/spring-security/site/docs/5.4.1/reference/html5/
1.怎样配置Security
官方示例:@EnableWebSecurity和继承WebSecurityConfigurerAdapter
2.授权
重写方法:protected void configure(HttpSecurity http) throws Exception
SecurityConfig.java
@EnableWebSecurity //开启WebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//链式编程
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/vip1/**").hasRole("vip1")
.antMatchers("/vip2/**").hasRole("vip2")
.antMatchers("/vip3/**").hasRole("vip3");
http.formLogin();
}
}
这里的登录页面是Security自带的:
3.认证
重写方法:protected void configure(AuthenticationManagerBuilder auth) throws Exception
写在SecurityConfig.java中
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("gaolang").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3");
}
用户root可以访问vip1、vip2和vip3下的访问。
用户gaolang可以访问vip1和vip2下的访问,访问vip3下时为ErrorPage:
但是实际情况是这些用户来自数据库,而不是自己定义:
数据库身份认证:
导入相关依赖:参考文章:【Spring Boot】数据库连接和Druid使用
- 首先连上我们的数据库
- 数据库中user表:
- 建好与数据库表相应的实体类
- 实现一些方法:
User getUserByName(String name);
- 写一个Service类继承接口UserDetailsService
@Component
public class CustomUserDetailService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//通过name===》获得这个User
User user = userMapper.getUserByName(s);
if (user == null){
throw new UsernameNotFoundException("用户不存在");
}
//取出角色
String roles = user.getRoles();
//角色集合
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
//必须以ROLE_开头
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_"+roles));
return new org.springframework.security.core.userdetails.User(user.getName(),
new BCryptPasswordEncoder().encode(user.getPwd()),grantedAuthorities);
}
}
- 完整的SecurityConfig类:
@EnableWebSecurity //开启WebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//链式编程
http.authorizeRequests().antMatchers("/","/get_auth").permitAll()
.antMatchers("/vip1/**").hasRole("vip1")
.antMatchers("/vip2/**").hasRole("vip2")
.antMatchers("/vip3/**").hasRole("vip3");
http.formLogin();
http.logout().logoutSuccessUrl("/to_login");
// http.rememberMe();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/*auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("gaolang").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3");*/
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
}
4.注销
加在授权的方法中,logoutSuccessUrl是指注销后跳转到的页面,这里是首页
http.logout().logoutSuccessUrl("/");
在前端需要使用注销时,设置a标签:/login和/logout都时Security提供的
<a th:href="@{/logout}"></a>
5.自定义登录页面
Spring Security自定义了login页面,我们不用它的,用自己的:
修改SecurityConfig.java里面的授权代码:
http.formLogin().loginPage("/to_login").passwordParameter("pwd").usernameParameter("user");
两个input标签,对应 用户名和密码 ,两个标签的name属性分别为user和pwd
http.formLogin().loginPage("/to_login");
不设置其他的,从源码可以看出name属性是默认是username和password
login.html:th:action="@{/to_login}"
这个action就是返回我们的login.html对应loginPage("/to_login")
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<h1 align="center">登录页面</h1>
<form th:action="@{/to_login}" method="post">
用户名:<input type="text" name="user">
密码:<input type="text" name="pwd">
<input type="submit" value="提交">
</form>
</div>
</body>
</html>
6.RememberMe功能
- 我们没有设置自己的登录页面,使用Security提供的:
在SecurityConfig.java里面的授权代码中添加:http.rememberMe();
- 设置了自己的登录页面:
<input type="checkbox" name="remember">记住我
在SecurityConfig.java里面的授权代码中添加:http.rememberMe().rememberMeParameter("remember");