Spring Security详细学习第二篇(授权,异常处理,跨域)

SpringSecurity

授权

权限系统可以使得不同的用户可以使用不同的功能

所以我们需要在后端进行相应的权限判断,判断当前用户是否具有相应的权限,必须基于所需权限才能进行相应的操作

  • 授权原理

在SpringSecurity中,会使用默认的FilterSecurityInterceptor来进行权限校验,在FilterSecurityInterceptor中会从securityContextHolder获取其中的Authentication,然后获取其中的权限信息,当前用户是否拥有访问当前资源所需的权限

框架提供了基于注解的权限控制的方案:

开启权限注解的相关配置:

java 复制代码
@EnableGlobalMathodSecurity(prePostEnabled= true)

注解放在所继承WebSecurityConfigurerAdapter的配置类上

然后可以使用对应的权限注解

java 复制代码
@RestController
public class HelloController{
   @RequestMapping("/hello")
   @PreAuthorize("hasAuthority('test')")
   public String hello(){
       return "hello";
   }
}

注解中的hasAuthority是一个方法,在进行判断的时候根据注解中传入的参数进行方法来进行判断

我们需要对UserDetails中完善授权信息部分:

在实现UserDetails的实现类中由方法getAuthorities()来返回控制权限的信息

java 复制代码
public class userdatails implements UserDetails{
     private List<String> primissions;
     @JSONField(serialize=false)
     private List<SimpleGrantedAuthority> authorities;
     public Colletion<? extends GrantedAuthority> getAuthorities(){
       if(authorities!=null)
       {
          return authorities;
       }
       authorities=permissions.stream()
               .map(SimpleGrantedAuthority::new)
               .collect(Collectors.toList());
       return authorities;
     }
}

在这个之中我们从数据库访问回来的权限信息放在List集合之中,但是在重写的方法getAuthorities()中它的返回信息是一个继承自GrantedAuthority的对象集合,我们需要将权限信息封装成每一个它的子类对象SimpleGrantedAuthority但是我们需要将控制信息放在redis中,不能够将spring提供的该对象进行序列化保存,所以我们需要通过注解 @JSONField对这个对象集合进行忽略,我们只需要将primissions进行序列化保存即可

在实现UserDetailsService的实现类中,我们封装一个权限集合并同User信息一起返回

java 复制代码
public class UserDetailsserviceimpl implements UserDetailsService{
 
    //封装一个权限的List集合
    List<String> list=new ArrayList<>(Arrays.asList("test"));
    return new User(user,list);
}

在jwt过滤器中再将之前封装到UserDetails的权限信息封装到Authentication中

具体的过滤器请看博主第一篇,博主在这里对之前的内容进行添加

java 复制代码
  UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(user,null,user.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

从数据库中获取权限信息

RBAC权限模型

RBAC权限模型(Role-Based Access Control)基于角色的权限控制

上述我们在获取数据库中权限信息中我们直接给定权限信息:

java 复制代码
   List<String> list=new ArrayList<>(Arrays.asList("test"));

但在真实中是通过数据库来的

我们可以将所有的操作权限放在一个权限表中:

id 权限信息
1 删除图书
2 查看图书

比如这样的表中,这时我们应该为用户表中的用户配备它的权限,但是由于权限太多,我们需要在启用一个表角色表,将对应的很多权限成组赋予这个角色,而用户表中的每个用户就只用承担对应的角色即可

一个角色可以由多个权限,一个权限可以赋予多个角色,属于多对多的关系,我们可以在创建一个关联表来实现它的关联关系

例如:

角色id 权限id
1 1
1 2
2 2

而用户和角色之间也是一个多对多的关系也需要一个关联表来实现它们的关系

创建权限对应的实体类 (我们默认实体类为qxtable)

在Mapper层下实现一个查询权限信息的多表查询的操作,再将查询到的权限字符串封装到List集合当中在封装到UserDetails中

异常处理

在SpringSecurity中,如果我们在认证或者授权失败之后异常会被ExceptionTranslationFilter过滤器捕获到,

如果是认证失败出现的异常会被封装到AuthenticationException然后调用AuthenticationEntryPoint对象的方法去进行异常处理

如果是认证过程中出现的异常会被封装为AccessDeniedException然后调用AccessDenielHandler对象的方法去进行异常处理

将上述两个对象配置到SpringSecurity的配置类当中

java 复制代码
//配置异常处理器
http.exceptionHandling()
     
     .authenticationEntryPoint(authenticationEntryPoint)
     .accessDeniedHandler(accessDeniedHandler)

跨域问题

跨域问题通常是由浏览器的安全策略所引起的,称为同源策略(Same-Origin Policy),它限制了页面从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。

我们通过SpringMVC提供的WebMvcConfigurer接口可以配置CORS头部,来解决跨域请求问题:

java 复制代码
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //设置允许跨域的路径
        registry.addMapping("/**")
                 //设置允许跨域请求的域名
                .allowedOrigins("*")
                //设置允许的请求方式
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                //设置允许的header属性
                .allowedHeaders("Content-Type", "Authorization")
                //是否允许使用cookie
                .allowCredentials(true)
                //跨域允许时间
                .maxAge(3600);
    }
}

上述是SpringBoot中允许跨域的配置,但是在使用了SpringSecurity之后,由于资源被SpringSecurity进行保护,所以我们要进行跨域访问还要让SpringSecurity运行跨域访问

这里我们仍然在SpringSecurity中的configure方法中进行跨域配置

java 复制代码
//允许跨域配置
http.cors();
相关推荐
fly_over4 小时前
AI Agent 开发实战教程(三):记忆与数据库集成
数据库·人工智能·python·ai agent
@杰克成4 小时前
Java学习28
java·python·学习
星幻元宇VR4 小时前
VR科普大空间|法治、禁毒、消防一体化沉浸式教育新模式
科技·学习·安全·vr·虚拟现实
中国胖子风清扬4 小时前
PageIndex:用推理替代向量的下一代 RAG 架构
java·spring boot·python·spring·ai·embedding·rag
我的xiaodoujiao4 小时前
API 接口自动化测试详细图文教程学习系列19--添加封装其他的方法
开发语言·python·学习·测试工具·pytest
落痕的寒假4 小时前
[深度学习] 大模型学习8上-推理部署框架llama.cpp与Ollama使用指北
深度学习·学习·llama
诙_4 小时前
C++学习总结
开发语言·c++·学习
xieliyu.4 小时前
我的第 128 天创作里程碑:从 C 语言入门到 Java 学习之路
学习
承渊政道5 小时前
【贪心算法】(经典实战应用解析(三):K次取反后最⼤化的数组和、按⾝⾼排序、优势洗牌、最⻓回⽂串、增减字符串匹配)
数据结构·c++·学习·算法·贪心算法·线性回归·哈希算法
长谷深风1115 小时前
SpringBoot开发秘籍【个人八股】
java·spring boot·后端·spring·八股