SpringSecurity系列之授权与注解

2022-08-03 13:07:55

SpringSecurity系列之授权与注解

本文中所使用的技术栈如下:
SpringBoot 2.6.2
MyBatis Plus 3.5.0
SpringSecurity 5.6.1

本文中的代码将基于上文[SpringSecurity系列之基于数据库认证]

一、基于配置类的权限控制

1.修改SpringSecurity配置类

重写configure(HttpSecurity http) 方法,给用户访问的URL中的路径进行权限限制,限定只有该角色或者权限的用户才能够进行访问。

@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{
   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实现类中设置用户的权限/角色,代码如下:

@OverridepublicUserDetailsloadUserByUsername(String username)throwsUsernameNotFoundException{// 通过username查询数据库中的用户信息QueryWrapper<SysUser> queryWrapper=newQueryWrapper<>();
   queryWrapper.eq("username", username);// 获取数据库查询的用户信息SysUser sysUser=this.userMapper.selectOne(queryWrapper);// 校验用户对象是否存在if(Objects.isNull(sysUser)){thrownewUsernameNotFoundException("用户不存在");}User.UserBuilder builder=User.builder();UserDetails admin= builder.username(sysUser.getUsername())// 实际上是从数据库中直接取出加密后的密码,而不是在此处加密.password(newBCryptPasswordEncoder().encode(sysUser.getPassword())).roles("admin").build();// 返回用户对象return admin;}

代码中构造UserDetails对象时调用的roles方法就是给该登录用户设置admin角色。

3.创建角色对应的接口

我们创建两个两个匹配路径的接口用于测试角色授权

@GetMapping("/test-user")publicStringtestUser(){return"SpringSecurity-user";}@GetMapping("/test-admin")publicStringtestAdmin(){return"SpringSecurity-admin";}

4.测试标题权限访问

测试结果如下:
在这里插入图片描述
在这里插入图片描述

如上当我们访问/test-user接口时,报403异常,表示我们没有访问该接口的权限,因为我们只有admin角色,而没有设置user角色。

5.自定义403无权访问页面

在static目录下创建一个403.html文件,内容如下:

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>403</title></head><body><h1>很抱歉,您没有访问权限!</h1></body></html>

在SpringSecurity配置类中添加自定义403访问页面的路径

@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{
   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)publicclassSecurityConfigextendsWebSecurityConfigurerAdapter{// ....}

在SpringSecurity配置类中或者SpringBoot启动类上添加 @EnableGlobalMethodSecurity注解,并设置securedEnabled属性值为ture 表示开启@Secured注解的使用。

创建一个接口并添加@Secured注解控制接口的访问权限,代码如下:

@Secured({"ROLE_admin"})@GetMapping("/test-user2")publicStringtestUser2(){return"SpringSecurity-user2";}

@Secured注解中添加字符串数组,每一个字符串数组代码一个角色,角色必须以ROLE_开头。
而在UserDetailsService实现类中给用户对象添加角色为ROLE_以后的字符串,如下:

UserDetails admin= builder.username(sysUser.getUsername())// 实际上是从数据库中直接取出加密后的密码,而不是在此处加密.password(newBCryptPasswordEncoder().encode(sysUser.getPassword())).roles("admin").build();

访问结果如下:
在这里插入图片描述

2.@PreAuthorize注解的使用

使用该注解同样需要开启配置@EnableGlobalMethodSecurity注解,不过是需要设置prePostEnabled属性为true。
代码如下:

@Configuration@EnableGlobalMethodSecurity(prePostEnabled=true)publicclassSecurityConfigextendsWebSecurityConfigurerAdapter{// ...}

创建一个接口并添加@PreAuthorize注解

@PreAuthorize("hasRole('ROLE_admin')")@GetMapping("/test-user3")publicStringtestUser3(){return"SpringSecurity-user3";}

在该注解中需要添加的是角色权限的表达式,以现在用户访问的权限。
上述接口中表示访问该接口必须有admin角色

在@PreAuthority注解中角色可以不用添加ROLE_前缀,系统将会自动帮我们添加前缀

@PreAuthorize("hasRole('admin')")@GetMapping("/test-user5")publicStringtestUser5(){return"SpringSecurity-user5";}

使用如上代码也可完成admin角色控制接口

其他表达式:

  • hasAnyRole: 可添加多个角色,而hasRole只可添加一个角色
  • hasAuthority: 添加一个访问权限,只能添加一个
  • hasAnyAuthority: 添加多个访问权限
UserDetails admin= builder.username(sysUser.getUsername())// 实际上是从数据库中直接取出加密后的密码,而不是在此处加密.password(newBCryptPasswordEncoder().encode(sysUser.getPassword()))// .roles("admin").authorities("auth1").build();

如上代码给用户添加访问权限,通过调用authorities方法,设置访问权限。

警告:roles()和authorities()只能生效一个,后调用的会覆盖之前调用的权限,如上将roles()注释掉,即使不注释掉改方法,也无法使其生效。

  • permitAll() : 表示只需登录即可访问,无需任何权限
  • denyAll(): 表示拒绝访问,任何权限均无法访问
  • isAnonymous(): 表示匿名用户可访问

3.@PostAuthorize注解的使用

使用方式与第二点相同,区别在于该注解的权限校验是进入方法之后,在返回结果之前进行校验。

注解中的SpEL表达式参考SecurityExpressionRoot 类中的方法。

  • 作者:kenewstar
  • 原文链接:https://blog.csdn.net/weixin_45840947/article/details/122743588
    更新时间:2022-08-03 13:07:55