spring-security + spring-boot + mybatisPlus用户权限访问控制
- 1)基础原理
- 1)web权限方案
- 3)获取数据库用户信息以及对用户的增删改查以及授权(important)
- 1、查询数据库完成用户认证
- 2、自定义登录页面
- 3、web授权方案:用户授权(基于权限访问控制)
- (1)hasAuthority() ---如果当前的主体具有指定的权限,有的话true,没有false
- (2)hasAnyAuthority() ---如果当前的主体具有指定的权限,有的话true,没有false
- (3)hasRole() ---如果当前用户为指定角色,则返回true![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5ace525476fc7c06c90ef6a7078915bf.png)
- (4)hasAnyRole() ---如果当前用户为指定多个角色,则返回true![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/57347db8ff3470e41048d19f6772f4ad.png)
- 4、web授权方案:自定义403无权访问界面
- 5、web授权方案:自定义安全退出操作
1)基础原理
Spring-Security本质是一个过滤器链,有很多的过滤器
通过查看源码
FilterSecurityIntercepter //这是一个方法级的权限过滤器,基本位于过滤链的最底部
ExceptionTranslationFilter //这是个异常过滤器,用来处理再认证授权时过程中抛出的异常
UsernamePasswordAuthenticationFilter //这是一个对/login的POST请求做拦截,校验表单中的用户名和密码等功能
两个重要的接口:
UserDetailsService接口 :查询数据库和用户名和密码过程
1、创建类继承UsernamePasswordAuthenticationFilter,重写里的三个方法
2、创建类实现UserDetailService,编写查询数据过程,返回User对象,这个User对象是安全框架提供的对象
PasswordEncoder接口:数据加密接口,用于返回User对象里面的密码加密
1)web权限方案
设置登录的用户名和密码:第一种方式:通过配置文件。第二种方式:通过配置类。第三种方式:自定义编写实现类
1、配置appication.properties文件设置登录的用户名和密码
2、通过配置类配置用户名和密码
spring.security.user.name=admin
spring.security.user.password=123456
3、自定义实现类
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private UserDetailsService uds; //注入用户服务信息
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
BCryptPasswordEncoder bpe = new BCryptPasswordEncoder();
auth.userDetailsService(uds).passwordEncoder(bpe);
}
}
@Service("uds")
public class MyUserDetailService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<GrantedAuthority> authn = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admin");
return new User("username",
new BCryptPasswordEncoder().encode("123456"),authn);
}
}
3)获取数据库用户信息以及对用户的增删改查以及授权(important)
1、查询数据库完成用户认证
这里需要整合mybatisPlus完成数据库操作或者jdbc
(1)引入相关依赖:
<!-- mybatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok简化实体类 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
(2)创建sql表格信息:
(3)配置实体类:
package entity;
import lombok.Data;
public class Users {
private int id;
private String username;
private String password;
@Override
public String toString() {
return "Users{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
public Users() {
}
public Users(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
(4)整合mp,创建接口,继承mp的接口
package com.hxzy.springscuritydamo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import entity.Users;
import org.springframework.stereotype.Repository;
/**
* @BaseMapper 这个接口里实现了对数据库的增删改查操作,直接调用里面的方法就可以了
* @Repository
* */
@Repository
public interface UserMapper extends BaseMapper<Users> {}
(5)在MyUserDetailsService调用mapper里面的方法查询数据库进行用户认证
package com.hxzy.springscuritydamo.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hxzy.springscuritydamo.mapper.UserMapper;
import entity.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service("uds")
public class MyUserDetailService implements UserDetailsService {
@Autowired
private UserMapper usersMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//调用userMapper方法,根据用户名查询数据库
QueryWrapper<Users> wrapper = new QueryWrapper<>();
wrapper.eq("username",username);
Users users = usersMapper.selectOne(wrapper);
//判断
if (users == null){ //如果数据库里没有用户名,则认证失败
throw new UsernameNotFoundException("用户不存在");
}
//查数据库,得到密码,得到用户名,得到s权限
List<GrantedAuthority> authn = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admin");
return new User(users.getUsername(),
new BCryptPasswordEncoder().encode(users.getPassword()),authn);
}
}
(6)在启动类添加注解MapperScan
package com.hxzy.springscuritydamo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.hxzy.springscuritydamo.mapper")
@SpringBootApplication
public class SpringscuritydamoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringscuritydamoApplication.class, args);
}
}
(7)数据库application.properties配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/demo?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
2、自定义登录页面
(1)在配置类实现相关配置
package com.hxzy.springscuritydamo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import javax.sql.DataSource;
import java.beans.PersistenceDelegate;
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private UserDetailsService uds; //注入用户服务信息
@Autowired
private DataSource dataSource;//注入数据源
//配置对象
@Bean
public PersistentTokenRepository ptr(){
JdbcTokenRepositoryImpl jtr = new JdbcTokenRepositoryImpl();
jtr.setDataSource(dataSource);
// jtr.setCreateTableOnStartup(true);
return jtr;
}
// @Override
// public void addViewControllers(ViewControllerRegistry registry){
// registry.addViewController("/").setViewName("forword:/login.html");
// registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
// }
//实现用户身份认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
BCryptPasswordEncoder bpe = new BCryptPasswordEncoder();
auth.userDetailsService(uds).passwordEncoder(bpe);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//配置Url的权限访问
// http.authorizeRequests()
// .antMatchers("/").permitAll()
// .antMatchers("/**update**").permitAll()
// .antMatchers("login/**").permitAll()
// .anyRequest().authenticated();
http.csrf().disable(); //关闭csrf防护
//配置没有访问权限页面403页面
http.exceptionHandling().accessDeniedPage("/error.html");
//安全退出
http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/login").permitAll();
//loginpage()->自定义登录页面设置,loginProcessingUrl()->登录访问的路径,defaultSuccessUrl()->登录成功后访问的页面
http.formLogin().loginPage("/test/login")//自己配置的登录页面
.loginProcessingUrl("/user/login")
.defaultSuccessUrl("/test/index")
.failureUrl("/test/error").permitAll()
.and().authorizeRequests()
.antMatchers("/","/test/hello","/user/login").permitAll() //设置哪些路径可以直接访问,不需要认证
//1、hasAuthority:当前登录用户,只有具有admins权限的用户才能访问这个路径
//.antMatchers("/test/index").hasAuthority("admins")
//2、hasAnyAuthority:当前登录用户,自定义权限的用户才能访问这个路径
//.antMatchers("/test/index").hasAnyAuthority("admins,manager")
//3、hasRole:
//.antMatchers("/test/index").hasRole("saler")
//4、hasAnyRole:
.antMatchers("/test/index").hasAnyRole("sale,manager,admin,user")
.anyRequest().authenticated()
}
}
(2)创建相关页面/test/login、/test/index
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
form{
width: 240px;
}
span{
display: block;
margin-top: 10px;
}
input{
float: right;
}
</style>
</head>
<body>
<form action="/user/login" method="post">
<!-- <input th:name="${_csrf.parameterName}" th:value="${_csrf.token}" type="hidden"/>-->
<span>用户名:<input type="text" name="username" /></span>
<span>密码:<input type="password" name="password" /></span>
<span>单点登录<input style="float: none" type="checkbox" name="remember-me" /></span>
<input style="cursor: pointer;" type="submit" value="登录" />
</form>
</body>
</html>
3、web授权方案:用户授权(基于权限访问控制)
4个方法:hasAuthority()、hasAnyAuthority()、hasRole()、hasAnyRole()
(1)hasAuthority() —如果当前的主体具有指定的权限,有的话true,没有false
1:在配置类中设置当前访问地址有哪些权限
http.antMatchers("test/index").hasAuthortiy("admins")
2:在UserDetailsService,把返回User对象设置权限
List<GrantedAuthority> authn = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
如果访问地址的权限与返回User对象权限不一致,则跳到403界面无权访问
(2)hasAnyAuthority() —如果当前的主体具有指定的权限,有的话true,没有false
1:在配置类中设置当前访问地址有哪些权限
.antMatchers("/test/index").hasAnyAuthority("admins,manager");
2:在UserDetailsService,把返回User对象设置任意在配置类中存在的权限
List<GrantedAuthority> authn = AuthorityUtils.commaSeparatedStringToAuthorityList("admins");
(3)hasRole() —如果当前用户为指定角色,则返回true
(4)hasAnyRole() —如果当前用户为指定多个角色,则返回true
4、web授权方案:自定义403无权访问界面
在配置类进行配置
5、web授权方案:自定义安全退出操作
在配置类进行配置