SpringSecurity系列之授权与注解

SpringSecurity系列之授权与注解,第1张

SpringSecurity系列之授权与注解 SpringSecurity系列之授权与注解

本文中所使用的技术栈如下:
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查询数据库中的用户信息
   QueryWrapper queryWrapper = 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();

访问结果如下:

2.@PreAuthorize注解的使用

使用该注解同样需要开启配置@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 类中的方法。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5717650.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存