本文中所使用的技术栈如下:
SpringBoot 2.6.2
MyBatis Plus 3.5.0
SpringSecurity 5.6.1
本文中的代码将基于上文[SpringSecurity系列之基于数据库认证]
一、基于配置类的权限控制 1.修改SpringSecurity配置类重写configure(HttpSecurity http) 方法,给用户访问的URL中的路径进行权限限制,限定只有该角色或者权限的用户才能够进行访问。
@Override protected void configure(HttpSecurity http) throws Exception { http.formLogin(); http.authorizeRequests() // 有该角色才能访问 .antMatchers("/test-user").hasRole("user") .antMatchers("/test-admin").hasRole("admin") // 登录可访问 .anyRequest().authenticated(); //关闭csrf http.csrf().disable(); }
上述代码中所示,匹配/test-user的路径必须有user角色才能够访问,匹配 /test-admin 的路径必须有admin角色才能够访问,.anyRequest().authenticated(); 表示其他的任何请求只需登录即可访问。
2.修改UserDetailsService实现类进行用户授权而用户的授权我们在UserDetailsService实现类中设置用户的权限/角色,代码如下:
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 通过username查询数据库中的用户信息 QueryWrapperqueryWrapper = new QueryWrapper<>(); queryWrapper.eq("username", username); // 获取数据库查询的用户信息 SysUser sysUser = this.userMapper.selectOne(queryWrapper); // 校验用户对象是否存在 if (Objects.isNull(sysUser)) { throw new UsernameNotFoundException("用户不存在"); } User.UserBuilder builder = User.builder(); UserDetails admin = builder.username(sysUser.getUsername()) // 实际上是从数据库中直接取出加密后的密码,而不是在此处加密 .password(new BCryptPasswordEncoder().encode(sysUser.getPassword())) .roles("admin") .build(); // 返回用户对象 return admin; }
代码中构造UserDetails对象时调用的roles方法就是给该登录用户设置admin角色。
3.创建角色对应的接口我们创建两个两个匹配路径的接口用于测试角色授权
@GetMapping("/test-user") public String testUser() { return "SpringSecurity-user"; } @GetMapping("/test-admin") public String testAdmin() { return "SpringSecurity-admin"; }4.测试标题权限访问
测试结果如下:
如上当我们访问/test-user接口时,报403异常,表示我们没有访问该接口的权限,因为我们只有admin角色,而没有设置user角色。
5.自定义403无权访问页面在static目录下创建一个403.html文件,内容如下:
403 很抱歉,您没有访问权限!
在SpringSecurity配置类中添加自定义403访问页面的路径
@Override protected void configure(HttpSecurity http) throws Exception { http.formLogin(); http.authorizeRequests() // 有该角色才能访问 .antMatchers("/test-user").hasRole("user") .antMatchers("/test-admin").hasRole("admin") // 登录可访问 .anyRequest().authenticated(); // 设置403访问页面 http.exceptionHandling().accessDeniedPage("/403.html"); //关闭csrf http.csrf().disable(); }
如图中代码,接下来我们访问/test-user接口,结果如下:
基于注解的权限控制比较简单,我们只需要在接口方法上添加权限注解,并开启注解配置即可。
1.@Secured注解的使用使用该注解做权限控制需要开启如下配置:
@Configuration @EnableGlobalMethodSecurity(securedEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { // .... }
在SpringSecurity配置类中或者SpringBoot启动类上添加 @EnableGlobalMethodSecurity注解,并设置securedEnabled属性值为ture 表示开启@Secured注解的使用。
创建一个接口并添加@Secured注解控制接口的访问权限,代码如下:
@Secured({"ROLE_admin"}) @GetMapping("/test-user2") public String testUser2() { return "SpringSecurity-user2"; }
@Secured注解中添加字符串数组,每一个字符串数组代码一个角色,角色必须以ROLE_开头。
而在UserDetailsService实现类中给用户对象添加角色为ROLE_以后的字符串,如下:
UserDetails admin = builder.username(sysUser.getUsername()) // 实际上是从数据库中直接取出加密后的密码,而不是在此处加密 .password(new BCryptPasswordEncoder().encode(sysUser.getPassword())) .roles("admin") .build();
访问结果如下:
使用该注解同样需要开启配置@EnableGlobalMethodSecurity注解,不过是需要设置prePostEnabled属性为true。
代码如下:
@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { // ... }
创建一个接口并添加@PreAuthorize注解
@PreAuthorize("hasRole('ROLE_admin')") @GetMapping("/test-user3") public String testUser3() { return "SpringSecurity-user3"; }
在该注解中需要添加的是角色权限的表达式,以现在用户访问的权限。
上述接口中表示访问该接口必须有admin角色
在@PreAuthority注解中角色可以不用添加ROLE_前缀,系统将会自动帮我们添加前缀
@PreAuthorize("hasRole('admin')") @GetMapping("/test-user5") public String testUser5() { return "SpringSecurity-user5"; }
使用如上代码也可完成admin角色控制接口
其他表达式:
hasAnyRole: 可添加多个角色,而hasRole只可添加一个角色hasAuthority: 添加一个访问权限,只能添加一个hasAnyAuthority: 添加多个访问权限
UserDetails admin = builder.username(sysUser.getUsername()) // 实际上是从数据库中直接取出加密后的密码,而不是在此处加密 .password(new BCryptPasswordEncoder().encode(sysUser.getPassword())) // .roles("admin") .authorities("auth1") .build();
如上代码给用户添加访问权限,通过调用authorities方法,设置访问权限。
警告:roles()和authorities()只能生效一个,后调用的会覆盖之前调用的权限,如上将roles()注释掉,即使不注释掉改方法,也无法使其生效。
permitAll() : 表示只需登录即可访问,无需任何权限denyAll(): 表示拒绝访问,任何权限均无法访问isAnonymous(): 表示匿名用户可访问 3.@PostAuthorize注解的使用
使用方式与第二点相同,区别在于该注解的权限校验是进入方法之后,在返回结果之前进行校验。
注解中的SpEL表达式参考 SecurityexpressionRoot 类中的方法。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)