初始SpringSecurity安全框架

初始SpringSecurity安全框架

在介绍之前,我们先来体验一下SpringSecurity。
我们在一个新建springboot2的项目中,来引入依赖


    org.springframework.boot
    spring-boot-starter-security

  • 首先,用户通过Controller向未授权的资源发出未经身份验证的GetMapper请求/private。
  • 然后在浏览器URL中输入项目的启动端口+private,你就会发现自己跳转到了login登录页面,打开idea发现控制台多了一串字符串,通过用户名=user + 密码=字符串可以登录成功,并访问到private,这就是接下来要讲的。

认证(你是谁?)

表单登录

本节检查基于表单的登录在 Spring 安全性中的工作原理。 首先,我们看到用户如何被重定向到登录表单:

loginurlauthenticationentrypoint.png

  • 一、Spring Security的AuthorizationFilter设置了anyRequest().authenticated(); //默认拦截所有的请求。
  • 二、AuthorizationFilter如果访问被拦截则会通过ExceptionTranslationFilter(处理安全异常的安全过滤器)处理.AccessDeniedException异常。
  • 三、由于用户未经过身份验证,因此ExceptionTranslationFilter会启动身份验证,并使用配置的 AuthenticationEntryPoint 将重定向到登录页面。
  • 四、重定向到login页面
    用户提交用户名和密码后,将对用户名和密码进行身份验证。
    身份验证处理过滤器
    usernamepasswordauthenticationfilter.png

在此拦截器中验证用户名和密码是否正确,并指向到不同的拦截器链进行处理。

授权(你能做什么)

我们可以使用authorizeHttpRequests来定制不同的放行策略。

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
    http
        // ...
        .authorizeHttpRequests(authorize -> authorize
            .requestMatchers("/resources/**", "/signup", "/about").permitAll()
            .requestMatchers("/admin/**").hasRole("ADMIN")
            .requestMatchers("/db/**").access(new WebExpressionAuthorizationManager("hasRole('ADMIN') and hasRole('DBA')"))
            // .requestMatchers("/db/**").access(AuthorizationManagers.allOf(AuthorityAuthorizationManager.hasRole("ADMIN"), AuthorityAuthorizationManager.hasRole("DBA")))
            .anyRequest().denyAll()
        );

    return http.build();
}
  • 指定了多个授权规则。 每个规则都按照声明的顺序进行考虑。
  • 我们指定了任何用户都可以访问的多个 URL 模式。 具体而言,如果 URL 以“/resources/”开头、等于“/signup”或等于“/about”,则任何用户都可以访问请求。
  • 任何以“/admin/”开头的 URL 都将仅限于具有“ROLE_ADMIN”角色的用户。 您会注意到,由于我们正在调用该方法,因此我们不需要指定“ROLE_”前缀。hasRole
  • 任何以“/db/”开头的 URL 都要求用户同时具有“ROLE_ADMIN”和“ROLE_DBA”。 您会注意到,由于我们使用的是表达式,因此不需要指定“ROLE_”前缀。hasRole
  • 4中的相同规则,可以通过组合多个.AuthorizationManager
  • 任何尚未匹配的 URL 都将被拒绝访问。 如果您不想意外忘记更新授权规则,这是一个很好的策略。

请求匹配

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .securityMatcher("/api/**")
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/user/**").hasRole("USER")
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin(withDefaults());
        return http.build();
    }
}
  • 配置为仅应用于以HttpSecurity/api/
  • 允许具有该角色的用户访问以 开头的网址/user/USER
  • 允许具有该角色的用户访问以 开头的网址/admin/ADMIN
  • 任何其他不符合上述规则的请求都需要身份验证

防范漏洞利用

针对跨站点请求伪造攻击(CSRF)攻击

在SpringSecurity中,默认是启用了防范CSRF策略,但可以设置禁用CSRF

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable());
        return http.build();
    }
}

在 Spring Security 中,专门提供了一个 CsrfFilter 来实现对 CSRF 的保护。CsrfFilter 拦截请求,并允许使用 GET、HEAD、TRACE 和 OPTIONS 等 HTTP 方法的请求。而针对 PUT、POST、DELETE 等可能会修改数据的其他请求,CsrfFilter 则希望接收包含 csrf_token 的消息头。如果这个消息头不存在或包含不正确的 csrf_token 值,应用程序将拒绝该请求并将响应的状态设置为 403。
CSRF攻击的原理是这样的:

CSRF攻击

CSRF的攻击者只是利用了通过认证的Cookie。
CsrfFilter就在返回给客户端的表单里隐藏域的Value里和请求头中放置随机值,并在服务端也放置这个随机值,在用户发送请求时来校验这个随机值是否正确,如果不正确则拒绝访问。

表单里的随机字符串

但是在微服务中不能使用这种方式,因为客户端访问了一次实例,下发了Token。但微服务的多模块及负载均衡的特性,我们下一次携带Token发送的请求,未必是上一次的实例。
后端可以把随机字符串存入到Redis里,响应给前端,前端携带字符串访问Redis来验证。

你可能感兴趣的:(初始SpringSecurity安全框架)