Files
rikako-note/spring/Spring Security/spring_security_sgg.md
2024-03-14 00:19:13 +08:00

5.1 KiB
Raw Permalink Blame History

Spring Security

Spring Security提供了authentication认证、authorization授权、protection against common attacks防御常见攻击的功能。

Spring Security提供了针对如下常见攻击的防御

  • CSRF
  • Http Headers
  • Http Requests

默认自动装配

当web项目引入Spring Security依赖后如果不做任何特殊处理Spring Security会默认为项目配置一个登录校验。当用户没有进行登录而访问页面时会拦截用户请求返回一个登录页在用户登录成功之后再会将url重定向到用户先前请求的页面。

Spring Security默认为项目做的操作

  1. 保护web项目的urlSpring Security要求与http接口进行的任何交互都需要进行身份认证
  2. Spring Security会在web项目启动时生成一个默认的用户用户名为user用户密码会通过日志打出
  3. Spring Security会为项目生成默认的登录和注销页面并提供了基本登录流程和注销流程
  4. 对于http请求如果在没有进行身份认证的情况下会重定向到登录页面

Spring Security底层结构

Spring Security底层通过Filter链来实现。

DelegatingFilterProxy

spring boot提供了Filter的实现类DelegatingFilterProxy该类将实际的过滤逻辑委托给另一个filter bean对象。

通过DelegatingFilterProxy可以将servlet container和spring容器结合起来将DelegatingFilterProxy对象作为filter注册到servlet container中然后DelegatingFilterProxy把实际过滤逻辑委托给spring context中的bean对象如此可以通过向spring容器中注册bean对象来自定义filter chain逻辑。

SecurityFilterChain

DelegationFilterProxy将filter逻辑委托给了FilterChainProxy。

而FilterProxyChain则是包含了SecurityFilterChain并且可以包含多个SecurityFilterChain。SecurityFilterChain中包含的才是多个filter bean对象。

如果FilterChainProxy中注册了多个SecurityFilterChain那么将由FilterChainProxy来决定实际调用哪个SecurityFilterChain。只有匹配的第一个SecurityFilterChain会被实际调用。

如果当spring容器中存在多个SecurityFilterChian bean对象那么可以通过@Order注解来指定SecurityFilterChain bean对象的顺序从而调整不同SecurityFilterChain的优先级

示例如下:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(Customizer.withDefaults())
            .authorizeHttpRequests(authorize -> authorize
                .anyRequest().authenticated()
            )
            .httpBasic(Customizer.withDefaults())
            .formLogin(Customizer.withDefaults());
        return http.build();
    }

}

上述代码注册的SecurityFilterChain将拥有如下顺序

Filter Added by
CsrfFilter HttpSecurity#csrf
UsernamePasswordAuthenticationFilter HttpSecurity#formLogin
BasicAuthenticationFilter HttpSecurity#httpBasic
AuthorizationFilter HttpSecurity#authorizeHttpRequests

通常security filter chain都是先执行authentication再执行authorization

自定义Filter

除了使用Spring Security预置的filter外还可以使用自定义的filter自定义filter使用示例如下

// Filter定义
import java.io.IOException;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import org.springframework.security.access.AccessDeniedException;

public class TenantFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        String tenantId = request.getHeader("X-Tenant-Id"); (1)
        boolean hasAccess = isUserAllowed(tenantId); (2)
        if (hasAccess) {
            filterChain.doFilter(request, response); (3)
            return;
        }
        throw new AccessDeniedException("Access denied"); (4)
    }

}
// 将自定义filter添加到SecurityFilterChain中
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        // ...
        .addFilterBefore(new TenantFilter(), AuthorizationFilter.class);
    return http.build();
}

授权

对于spring security其授权可以分为基于request的授权和基于方法的授权。

基于request的授权

基于request的授权可以根据用户-权限、用户-角色、用户-角色-权限进行实现。

基于方法的授权

基于方法的授权可以通过向方法添加权限注解来实现。