Spring Security- 基于角色的访问控制

发布时间:2024年01月17日

基于角色 或权限 进行访问控制

hasAuthority方法

如果当前的主体具有指定的权限,则返回true,否则返回false

修改配置类
? //当前登录用户 只有具备admins权限才可以访问这个路径
?.antMatchers("/test/index").hasAuthority("admins")

代码如下:

?package com.config;
??
?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 SecurityConfig extends WebSecurityConfigurerAdapter {
??
? ? ?@Autowired
? ? ?UserDetailsService userDetailsService;
??
??
? ? ?@Override
? ? ?protected void configure(AuthenticationManagerBuilder auth) throws Exception {
? ? ? ? auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
? ?  }
? ? ?@Bean
? ? ?PasswordEncoder passwordEncoder(){
? ? ? ? ?return new BCryptPasswordEncoder();
? ?  }
??
? ? ?@Override
? ? ?protected void configure(HttpSecurity http) throws Exception {
? ? ? ? ?http.formLogin().loginPage("/login.html") ? // 自定义登录页面
? ? ? ? ? ? ? ? ? ? ? ?  .loginProcessingUrl("/user/login") ? ? //登录访问路径
? ? ? ? ? ? ? ? ? ? ? ?  .defaultSuccessUrl("/test/index").permitAll() ? ? ?//登录成功后 跳转路径
? ? ? ? ? ? ? ? ? ? ? ?  .and().authorizeRequests()
? ? ? ? ? ? ? ? ? ? ? ?  .antMatchers("/","/user/login","/test/add").permitAll() //设置哪些路径可以不认证 直接访问
? ? ? ? ? ? ? ? ? ? ? ? ? //当前登录用户 只有具备admins权限才可以访问这个路径
? ? ? ? ? ? ? ? ? ? ? ?  .antMatchers("/test/index").hasAuthority("admins")
? ? ? ? ? ? ? ? ? ? ? ?  .and().csrf().disable() ; // 关闭csrf的防护
? ?  }
?}
修改 UserDetailsService, 把 返回的对象 设置权限

代码如下:

?
package com.service;
??
?import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
?import com.entity.UserInfo;
?import com.mapper.UserInfoMapper;
?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("userDetailsService")
?public class MyUserDetailsService implements UserDetailsService {
??
? ? ?@Autowired
? ? ?private UserInfoMapper userInfoMapper;
??
??
??
? ? ?@Override
? ? ?public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
??
? ? ? ? ?//根据用户名 查询
? ? ? ? ?QueryWrapper<UserInfo> wrapper=new QueryWrapper<>();
? ? ? ? ?wrapper.eq("name",username); ? //查询 name列 的值 为 username的 数据
? ? ? ? ?UserInfo info = userInfoMapper.selectOne(wrapper);
? ? ? ? ?//判断
? ? ? ? ?if(info==null){ ? //没有用户 验证失败
? ? ? ? ? ? ?throw new UsernameNotFoundException("用户名不存在");
? ? ? ?  }
??
? ? ? ? ?List<GrantedAuthority> list = AuthorityUtils.commaSeparatedStringToAuthorityList("admins"); ?//这里与配置类一致
? ? ? ? ?//返回数据库的用户名及密码
? ? ? ? ?return new User(info.getName(), new BCryptPasswordEncoder().encode(info.getPwd()),list);
? ?  }
?}

启动测试: 输入正确的用户名及密码, 当前返回的用户 具有admins 权限, 因此可以看到 hello index

接下来 将 上面UserDetailsService的 权限 由 admins改为其他 , 还是输入 正确的用户名及密码则There was an unexpected error (type=Forbidden, status=403).

hasAnyAuthority方法

如果当前的主体由任何提供的角色的话 返回true

修改配置类

具备 admins 或 abc 的 都可以 访问 /test/index

修改UserDetailsService

启动测试:

输入正确的用户名及密码 : 看到 hello index

hasRole

如果用户具备给定角色就允许访问 否则出现403

如果当前主体具有指定的角色则返回true

修改配置类

?package com.config;
??
?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 SecurityConfig extends WebSecurityConfigurerAdapter {
??
? ? ?@Autowired
? ? ?UserDetailsService userDetailsService;
??
??
? ? ?@Override
? ? ?protected void configure(AuthenticationManagerBuilder auth) throws Exception {
? ? ? ? auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
? ?  }
? ? ?@Bean
? ? ?PasswordEncoder passwordEncoder(){
? ? ? ? ?return new BCryptPasswordEncoder();
? ?  }
??
? ? ?@Override
? ? ?protected void configure(HttpSecurity http) throws Exception {
? ? ? ? ?http.formLogin().loginPage("/login.html") ? // 自定义登录页面
? ? ? ? ? ? ? ? ? ? ? ?  .loginProcessingUrl("/user/login") ? ? //登录访问路径
? ? ? ? ? ? ? ? ? ? ? ?  .defaultSuccessUrl("/test/index").permitAll() ? ? ?//登录成功后 跳转路径
? ? ? ? ? ? ? ? ? ? ? ?  .and().authorizeRequests()
? ? ? ? ? ? ? ? ?// ? ? ? /user/login","/test/add" 面允许任意访问
? ? ? ? ? ? ? ? ? ? ? ?  .antMatchers("/","/user/login","/test/add").permitAll() //设置哪些路径可以不认证 直接访问
? ? ? ? ? ? ? ? ? ? ? ? ? //当前登录用户 只有具备admins权限才可以访问这个路径
? ? ? ? ? ? ? ? ? ? ? ? ?//.antMatchers("/test/index").hasAnyAuthority("admins","abc")
? ? ? ? ? ? ? ? ? ? ? ?  .antMatchers("/test/index").hasRole("sale")
? ? ? ? ? ? ? ? ? ? ? ?  .anyRequest().permitAll()
? ? ? ? ? ? ? ? ? ? ? ?  .and().csrf().disable() ; // 关闭csrf的防护
? ?  }
?}
修改UserDetailsService

注意 配置类 写 sale , 这里需要增加前缀 ROLE_

?List<GrantedAuthority> list = AuthorityUtils.commaSeparatedStringToAuthorityList("admins,ROLE_sale");

启动 访问 输入正确 用户名 /密码 看到 hello index

hasAnyRole

表示用户具备任何一个条件都可以访问

修改配置类
?.antMatchers("/test/index").hasAnyRole("sale","p2")
修改UserDetailsService
?List<GrantedAuthority> list = AuthorityUtils.commaSeparatedStringToAuthorityList("admins,ROLE_p2");

启动访问 ,输入正确用户名/密码 可以看到 页面 hello index

自定义403页面

在static 下 建立 403.html

?<h1>未授权</h1>

在配置类进行配置:

?//配置没有权限访问跳转的页面
?http.exceptionHandling().accessDeniedPage("/403.html");

完整代码

?package com.config;
??
?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 SecurityConfig extends WebSecurityConfigurerAdapter {
??
? ? ?@Autowired
? ? ?UserDetailsService userDetailsService;
??
??
? ? ?@Override
? ? ?protected void configure(AuthenticationManagerBuilder auth) throws Exception {
? ? ? ? auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
? ?  }
? ? ?@Bean
? ? ?PasswordEncoder passwordEncoder(){
? ? ? ? ?return new BCryptPasswordEncoder();
? ?  }
??
? ? ?@Override
? ? ?protected void configure(HttpSecurity http) throws Exception {
??
? ? ? ? ?//配置没有权限访问跳转的页面
? ? ? ? ?http.exceptionHandling().accessDeniedPage("/403.html");
??
? ? ? ? ?http.formLogin().loginPage("/login.html") ? // 自定义登录页面
? ? ? ? ? ? ? ? ? ? ? ?  .loginProcessingUrl("/user/login") ? ? //登录访问路径
? ? ? ? ? ? ? ? ? ? ? ?  .defaultSuccessUrl("/test/index").permitAll() ? ? ?//登录成功后 跳转路径
? ? ? ? ? ? ? ? ? ? ? ?  .and().authorizeRequests()
? ? ? ? ? ? ? ? ?// ? ? ? /user/login","/test/add" 面允许任意访问
? ? ? ? ? ? ? ? ? ? ? ?  .antMatchers("/","/user/login","/test/add").permitAll() //设置哪些路径可以不认证 直接访问
? ? ? ? ? ? ? ? ? ? ? ? ? //当前登录用户 只有具备admins权限才可以访问这个路径
? ? ? ? ? ? ? ? ? ? ? ? ?//.antMatchers("/test/index").hasAnyAuthority("admins","abc")
? ? ? ? ? ? ? ? ? ? ? ? ?//.antMatchers("/test/index").hasRole("sale")
? ? ? ? ? ? ? ? ? ? ? ?  .antMatchers("/test/index").hasAnyRole("sale","p2")
? ? ? ? ? ? ? ? ? ? ? ?  .anyRequest().permitAll()
? ? ? ? ? ? ? ? ? ? ? ?  .and().csrf().disable() ; // 关闭csrf的防护
? ?  }
?}

修改 代码 让 其 没有权限 ,输入正确的用户名与密码

4注解方式

@secured

判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀 “ROLE"

使用注解先要开启注解功能!,

@EnableGlobalMethodSecurity(securedEnabled=true)

修改启动类或配置类 开启注解

选择 启动类

?@SpringBootApplication
?@MapperScan(basePackages = "com.mapper")
?@EnableGlobalMethodSecurity(securedEnabled = true)
?public class SSApp {
? ? ?public static void main(String[] args) {
? ? ? ? ?SpringApplication.run(SSApp.class,args);
? ?  }
?}

在controller 方法上 使用注解 ,设置 角色

?
package com.controller;
??
?import org.springframework.security.access.annotation.Secured;
?import org.springframework.web.bind.annotation.GetMapping;
?import org.springframework.web.bind.annotation.RequestMapping;
?import org.springframework.web.bind.annotation.RestController;
??
?@RestController
?@RequestMapping("/test")
?public class TestController {
??
? ? ?@GetMapping("/index")
? ? ?public String index(){
? ? ? ? ?return "hello index";
? ?  }
??
??
? ? ?@GetMapping("/add")
? ? ?public String add(){
? ? ? ? ?return "hello security";
? ?  }
??
??
??
? ? ?@GetMapping("/update") 
? ? ?@Secured({"ROLE_sale","ROLE_manager"}) ? ?---- 注解访问 ,需要在启动类 开启注解  ,注意前缀
? ? ?public String update(){
? ? ? ? ?return "hello update";
? ?  }
??
??
?}

在UserDetailsService 中 配置角色

?List<GrantedAuthority> list = AuthorityUtils.commaSeparatedStringToAuthorityList("admins,ROLE_sale");

启动 测试: 地址栏 输入 localhost:8080/test/update

然后输入 正确的用户名/密码 , 然后看到页面

@PreAuthorize

先开启注解功能

@EnableGlobalMethodSecurity(prePostEnabled = true)

@PreAuthorize:注解适合进入方法前的权限验证

@PreAuthorize可以将登录用户的roles/permissions参数传到方法中。。

使用方式:

在启动类开启注解

?@SpringBootApplication
?@MapperScan(basePackages = "com.mapper")
?@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled=true)
?public class SSApp {
? ? ?public static void main(String[] args) {
? ? ? ? ?SpringApplication.run(SSApp.class,args);
? ?  }
?}

在controller方法上添加注解

?@GetMapping("/update")
?//@Secured({"ROLE_sale","ROLE_manager"})
?@PreAuthorize("hasAnyAuthority('admins','abc')")
?public String update(){
? ? ?return "hello update";
?}

在UserDetailsService 中 配置角色或权限

?List<GrantedAuthority> list = AuthorityUtils.commaSeparatedStringToAuthorityList("admins,ROLE_sale");

启动测试:

@PostAuthorize

先开启注解功能

@EnableGlobalMethodSecurity(prePostEnabled = true)

@PostAuthorize 注解使用并不多, 在方法执行后进行权限验证,适合验证带有返回值的权限

开启注解

?
@SpringBootApplication
?@MapperScan(basePackages = "com.mapper")
?@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled=true)
?public class SSApp {
? ? ?public static void main(String[] args) {
? ? ? ? ?SpringApplication.run(SSApp.class,args);
? ?  }
?}

编写controller , 判断是否 具备 'admins','ROLE_abc'

?@GetMapping("/update")
?//@Secured({"ROLE_sale","ROLE_manager"})
?//@PreAuthorize("hasAnyAuthority('admins','abc')")
?@PostAuthorize("hasAnyAuthority('admins','abc')")
?public String update(){
? ? ?System.out.println("update.......");
? ? ?return "hello update";
?}

修改UserDetailsService , 让其拥有 admin 与 上面的 admins 不同

?List<GrantedAuthority> list = AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_sale");

启动测试 ,输入正确的用户名及密码 , 发现 具备admin 但没有 admins 权限, 控制台会打印 update.... ,然后显示 跳转到未授权页面403.html

@PostFilter 对返回数据做过滤

@PostFilter:权限验证之后对数据进行过滤,留下用户名是admin1的数据.

表达式中的 filterObject 引用的是方法返回值List中的某一个元素-

@PreFilter 对传入参数做过滤

@PreFilter 进入控制器之前对数据进行过滤

文章来源:https://blog.csdn.net/ly121862/article/details/135640422
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。