我们使用这个springSecurity安全框架,作用是认证,授权,将用户的权限和对应的资源进行绑定,默认的是在内存中保存的,实际开发中,是需要根据项目业务的需求对某些方法进行重写,使数据库中权限对应的资源进行绑定,就是查看当前登录的用户所扮演的角色,该角色有哪些权限
授权
1内存交互资源绑定
这是框架默认的绑定方式,根据业务需求可以重写某些方法,连接数据库,进行交互进行资源绑定
inMemoryAuthentication
1创建一个SpringBoot项目
2配置类MySecurityConfig
java
package com.aaa.config;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
//加密
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();//新建密码加密器
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//内存交互
auth.inMemoryAuthentication()
.withUser("zhangsan")
.password(passwordEncoder().encode("123456"))
.roles("admin")
.authorities("user:query", "user:delete", "user:update", "user:insert")//手动设置的用户权限绑定资源,有4个权限
.and()
.withUser("lisi")
.password(passwordEncoder().encode("123456"))
.roles("test")
.authorities("user:query", "user:export")//有两个权限
;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//登录前
http.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/mylogin")
.successForwardUrl("/success")
.failureUrl("/fail.html") // 直接指向一个HTML页面
.permitAll();
//登录后
http.exceptionHandling().accessDeniedPage("/403.html");
//禁止2跨域伪造请求的验证
http.csrf().disable();
http.authorizeRequests().anyRequest().authenticated();
}
}
3添加注解
java
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启安全框架注解
4在controller层加注解
在对应的方法上加注解
java
@PreAuthorize(value="hasAnyAuthority('user:query')")
java
package com.aaa.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyUserController {
@GetMapping("query")
@PreAuthorize(value="hasAnyAuthority('user:query')")
public String query(){
System.out.println("访问查询资源");
return "查询资源";
}
@GetMapping("delete")
@PreAuthorize(value = "hasAuthority('user:delete')")
public String delete(){
System.out.println("访问删除资源");
return "删除资源";
}
@GetMapping("update")
@PreAuthorize(value = "hasAuthority('user:update')")
public String update(){
System.out.println("访问修改资源");
return "修改资源";
}
@GetMapping("insert")
@PreAuthorize(value = "hasAuthority('user:insert')")
public String insert(){
System.out.println("访问添加资源");
return "添加资源";
}
@GetMapping("export")
@PreAuthorize(value = "hasAuthority('user:export')")
public String export(){
System.out.println("访问导出资源");
return "导出资源";
}
}
2与数据库交互进行权限的资源绑定
1添加依赖
java
<!--添加依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.6.13</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
2写属性文件
加载资源文件
3创建dao层和entity(实体类)
举一个接口和一个实体类例子
user-role-permission,
从用户表到角色表,再到权限表
sys_user--->sys_user_role--->sys_role_permission--->sys_permission
mybatis-plus先根据条件(用户的名)从用户表sys_user筛选,获取用户id,
然后拿着用户的id从用户角色表sys_user_role获取到用户所对应的roleid,
接着拿着roleid从角色权限表sys_role_permission获取permissionid,
再拿着权限id,(permissionid)到权限表sys_permission里获取所有全部权限信息,
最后绑定到用户上
sql语句
sql
select DISTINCT sys_permission.* from sys_permission
join sys_role_permission
on sys_permission.perid=sys_role_permission.perid
join sys_user_role
on sys_role_permission.roleid=sys_user_role.roleid
where sys_user_role.userid=#{userid}
4 写自己的业务层
根据业务需求,重写框架的某些默认方法,进行权限绑定
java
package com.aaa.service;
import com.aaa.dao.PermissionDao;
import com.aaa.dao.UserDao;
import com.aaa.entity.Permission;
import com.aaa.entity.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Service
public class MyUserDetailService implements UserDetailsService {
@Autowired
private UserDao userDao;
@Autowired
private PermissionDao permissionDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//完成根据账户查询数据库即可
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username",username);
User user = userDao.selectOne(queryWrapper);
if(user!=null){
//permissions集合,源类型的集合,源集合--->目标类型的集合转换
List<Permission> permissions = permissionDao.selectByUserId(user.getUserid());
//空的SimpleGrantedAuthority类型的数组,目标类型的集合
Collection<SimpleGrantedAuthority> authorities= new ArrayList<>();
for (Permission per:permissions) {
//把permissions集合里的东西拿出来,放到空集合里
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(per.getPercode());
authorities.add(simpleGrantedAuthority);
}
org.springframework.security.core.userdetails.User userDetail =
new org.springframework.security.core.userdetails.User(user.getUsername(),user.getUserpwd(),authorities);
return userDetail;
}
return null;
}
}
5再配置类MySecurityConfig
用自己写的业务替换掉框架给的
java
package com.aaa.config;
import com.aaa.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailService myUserDetailService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//数据库交互
auth.userDetailsService(myUserDetailService);
//内存交互
// auth.inMemoryAuthentication()
// .withUser("zhangsan")
// .password(passwordEncoder().encode("123456"))
// .roles("admin")
// .authorities("user:query","user:delete","user:update","user:insert")
// .and()
// .withUser("lisi")
// .password(passwordEncoder().encode("123456"))
// .roles("test")
// .authorities("user:query","user:export")//
;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/mylogin")
.successForwardUrl("/success")
.failureUrl("/fail.html") // 直接指向一个HTML页面
.permitAll();
// http.authorizeRequests()
// .antMatchers("/query").hasAnyAuthority("user:query")
// .antMatchers("/delete").hasAnyAuthority("user:delete")
// .antMatchers("/update").hasAnyAuthority("user:update")
// .antMatchers("/insert").hasAnyAuthority("user:insert")
// .antMatchers("/export").hasAnyAuthority("user:export");
http.exceptionHandling().accessDeniedPage("/403.html");
//禁止2跨域伪造请求的验证
http.csrf().disable();
http.authorizeRequests().anyRequest().authenticated();
}
}
总结
根据业务需求调用自己的业务层(自己写的),去代替框架的部门业务实现需求