基于角色 或权限 进行访问控制
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 {@AutowiredUserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@BeanPasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}@Overrideprotected 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 {@Autowiredprivate UserInfoMapper userInfoMapper;@Overridepublic 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 {@AutowiredUserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@BeanPasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}@Overrideprotected 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 {@AutowiredUserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@BeanPasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}@Overrideprotected 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 进入控制器之前对数据进行过滤