Spring Security

Spring Security是一个强大的安全框架,提供了认证、授权和防护机制。它基于RBAC权限模型,通过Authentication、UserDetailsService等接口实现用户认证和权限控制。框架支持自定义认证流程、权限管理,并提供了处理认证失败和权限不足的机制。同时,它还解决了跨域和CSRF攻击等常见安全问题,为Web应用提供全面的安全保护。

Spring Security

PreAuthorize 预授权

Authentication 认证

Authority 权限

SecurityContext 上下文对象,Authentication 对象会放在里面

SecurityContextHolder 用于拿到上下文对象的静态工具类

概要

启动依赖

​ 加入启动依赖后自动开启 Security 并生成登录页面

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
常见接口
  1. Authentication接口: 它的实现类,表示当前访问系统的用户,封装了用户相关信息。

  2. AuthenticationManager接口:定义了认证Authentication的方法

  3. UserDetailsService接口:加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。

  4. UserDetails接口:提供核心用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装成UserDetails对象返回。然后将这些信息封装到Authentication对象中。

过滤器责任链

img

权限模型
  • RBAC权限模型(Role-Based Access Control)即:基于角色的权限控制。这是目前最常被开发者使用也是相对易用、通用权限模型。

  • 创建这 5 张表

# 移步 01.sql

认证

判断一个用户是否为合法用户的过程 简称认证

授权

判断一个用户是否有执行对应操作的权限进行放行或拒绝操作的过程 简称授权

授权的流程

​ 在请求时,先经过自定义的过滤器(例 JWTAuthenticationTokenFilter 此过滤器要在SpringSecurity的校验用户名密码的过滤器前执行),将token解析将用户对象查出,然后将权限信息获取,并封装LoginUser和authorities到authentication中,并set到SecurityContextHolder中,交给SpringSecurity进行管理

预设的授权管理

使用预设的授权管理,在loginuser中存储Security所规定的SimpleGrantedAuthority权限对象

然后使用preAuthores注解在进入controller方法前使用 hasAuthority进行判断是否具有执行对应方法的权限

自定义授权管理

自己做一个类进行判断是否具有执行权限

在接口对应位置书写spel表达式时 写@bean名称.校验方法 进行判断

也可以使用配置方法给http指定antMatchers并指定权限要求

@PreAuthorize("@ex.hasAuthority('system:dept:list')")

失败的情况

未能通过认证,权限不足的情况出现时,默认操作没有给前端做出对应回应,我们要覆盖默认操作替换为自定义的操作

认证授权失败处理

​ SpringSecurity默认提供了两个接口AuthenticationEntryPoint,AccessDeniedHandler和两个默认的实现类来处理认证失败和权限不足的处理方式,要想替换这种方式,只需要手动实现这两个接口并交给IOC管理,然后在SpringSecurity的配置类中注入这两个对象,并设置到configure方法的 exceptionHandling()方法的对应方法中

  1. 两个实现类

    @Component
    public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
        @Override
        public void handle(HttpServletRequest request,
                           HttpServletResponse response,
                           AccessDeniedException accessDeniedException) throws IOException, ServletException {
    
            R<String> unAuthorized = new R<>(HttpStatus.HTTP_FORBIDDEN, "权限不足,操作失败。", null);
            WebUtils.renderString(response, new ObjectMapper().writeValueAsString(unAuthorized));
    
        }
    }
    
    @Component
    public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
        @Override
        public void commence(HttpServletRequest request,
                             HttpServletResponse response,
                             AuthenticationException authException) throws IOException, ServletException {
    
            R<String> unAuthorized = new R<>(HttpStatus.HTTP_UNAUTHORIZED, "用户认证失败,请重新登录。", null);
            WebUtils.renderString(response, new ObjectMapper().writeValueAsString(unAuthorized));
        }
    }
    
  2. 配置到SpringSecurity中

    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        //两个异常处理实现类
        @Autowired
        private AccessDeniedHandlerImpl accessDeniedHandler;
        @Autowired
        private AuthenticationEntryPointImpl authenticationEntryPoint;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            
            //添加认证失败 和 权限不足的异常处理
            http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
                .and()
                .exceptionHandling().accessDeniedHandler(accessDeniedHandler);
        }
    }
    

    跨域

    ​ 跨域是指,在前端发送请求时,浏览器会对不同源的请求进行限制(同源:域名,协议,端口号相同),在前后端分离的项目中,前端与后端大多数情况下是不同源的,要想允许不同源的请求,要分别配置springMvc和springSecurity允许不同源的访问

    1. 对SpringMvc配置允许跨域访问

      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.web.cors.CorsConfiguration;
      import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
      import org.springframework.web.filter.CorsFilter;
      
      @Configuration
      public class MvcConfig {
          /*
           * 配置 MVC 允许跨域
           */
          @Bean
          public CorsFilter corsFilter() {
              UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
              CorsConfiguration corsConfiguration = new CorsConfiguration();
              corsConfiguration.addAllowedOrigin("*");
              corsConfiguration.addAllowedHeader("*");
              corsConfiguration.addAllowedMethod("*");
              source.registerCorsConfiguration("/**", corsConfiguration);
              return new CorsFilter(source);
          }
      }
      
    2. 对Security配置允许跨域访问

      http.cors();
      

    CSRF攻击

    ​ CSRF 跨站请求攻击

    ​ 是指用户在访问A网站登录后,访问危险网站B,网站B可以伪造请求去访问网站A,此时浏览器会把网站A的cookie携带上,网站B就成功伪造了用户操作

    ​ 解决方式

    ​ 生成csrf_token且前端在请求时携带到请求头,而前后端分离的项目使用Token进行身份验证,天然免疫CSRF攻击。

    ​ 配置关闭csrf

    ​ SpringSecurity默认开启csrf防御,为了不让他去校验csrf_token导致请求失败,要手动配置关闭csrf

    http.csrf().disable();