SpringSecurity-前后端分离

在前后端分离的架构中,Spring Security 的配置与传统的单体应用有所不同。为了确保安全性和灵活性,我们需要对 Spring Security 进行适当的调整以适应这种架构。下面将详细介绍如何在前后端分离的应用程序中实现 Spring Security。

1. 理解前后端分离的安全需求

在前后端分离的应用程序中,前端通常是一个独立的 Web 应用或移动应用,而后端提供 RESTful API 或 GraphQL 接口。因此,我们需要考虑以下几点:

  • 认证:用户登录后,前端应该获得一个令牌(如 JWT),并在后续请求中携带此令牌来证明身份。
  • 授权:根据用户的权限级别,控制他们可以访问哪些资源。
  • 跨域资源共享 (CORS):由于前端和后端可能部署在不同的域名上,需要处理 CORS 请求。
  • 会话管理:避免使用基于 Cookie 的会话机制,转而采用无状态的身份验证方式。

2. 选择认证机制

对于前后端分离的应用,推荐使用 JSON Web Token (JWT)OAuth2 来进行认证。这里我们主要讨论 JWT 的实现。

2.1 JSON Web Token (JWT)

JWT 是一种自包含的令牌格式,它允许我们在客户端存储用户信息,并且可以在每次 HTTP 请求时通过 Authorization Header 发送到服务器。JWT 包含三个部分:Header、Payload 和 Signature。

  • 优点

    • 无状态:服务器不需要存储会话信息,减轻了服务器负担。
    • 跨域友好:易于在不同域名之间传递。
    • 简单易用:前端可以直接保存到 localStorage 或 sessionStorage 中。
  • 缺点

    • 安全性依赖于密钥管理:如果私钥泄露,所有签发的 JWT 都可能被伪造。
    • 不适合频繁更改权限场景:因为 JWT 是自签名的,一旦生成就难以撤销。

3. 配置 Spring Security

接下来我们将介绍如何配置 Spring Security 来支持 JWT 认证。

3.1 添加依赖

首先,在 pom.xml 文件中添加必要的依赖项:

XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
3.2 创建 JWT 工具类

创建一个工具类用于生成和解析 JWT:

java 复制代码
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

public class JwtUtil {

    private static final String SECRET = "your-secret-key"; // 私钥,请确保足够复杂

    public static String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .signWith(SignatureAlgorithm.HS512, SECRET.getBytes())
                .compact();
    }

    public static Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET.getBytes())
                .parseClaimsJws(token)
                .getBody();
    }
}
3.3 自定义过滤器

编写一个自定义过滤器来拦截每个请求并验证 JWT:

java 复制代码
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        String header = request.getHeader("Authorization");

        if (header != null && header.startsWith("Bearer ")) {
            try {
                String jwt = header.substring(7);
                Claims claims = JwtUtil.parseToken(jwt);

                // 设置当前线程的安全上下文
                SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
                        claims.getSubject(), null, Collections.emptyList()));
            } catch (Exception e) {
                logger.warn("Failed to set user authentication: {}", e.getMessage());
            }
        }

        filterChain.doFilter(request, response);
    }
}
3.4 配置 Spring Security

最后,配置 Spring Security 以集成 JWT 和 CORS 支持:

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .cors().and() // 启用 CORS 支持
            .csrf().disable() // 禁用 CSRF 保护(因为我们使用 JWT)
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 禁用会话
            .and()
            .authorizeRequests()
                .antMatchers("/auth/**").permitAll() // 允许未认证用户访问认证接口
                .anyRequest().authenticated(); // 所有其他请求都需要认证

        // 将自定义过滤器添加到过滤器链中
        http.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

4. 前端实现

在前端部分,你需要:

  • 在用户登录成功后保存返回的 JWT 到本地存储(如 localStoragesessionStorage)。
  • 在每次发送请求时,在 Authorization 头部添加 Bearer <token>
  • 当遇到 401 或 403 错误时,重定向至登录页面或显示适当的消息提示。
相关推荐
ThetaarSofVenice20 小时前
少一点If/Else - 状态模式(State Pattern)
java·设计模式·状态模式
前端杂货铺4 天前
Node.js——http 模块(一)
http·node.js·状态模式
難釋懷4 天前
状态模式详解与应用
设计模式·状态模式
计算机小混子4 天前
C++实现设计模式---状态模式 (State)
c++·设计模式·状态模式
多多*5 天前
后端技术选型 sa-token校验学习 下 结合项目学习 前后端登录
java·redis·git·学习·github·intellij-idea·状态模式
JINGWHALE18 天前
设计模式 行为型 状态模式(State Pattern)与 常见技术框架应用 解析
前端·人工智能·后端·设计模式·性能优化·系统架构·状态模式
摇光938 天前
js状态模式
开发语言·javascript·状态模式
Tatalaluola8 天前
【《游戏编程模式》实战04】状态模式实现敌人AI
学习·游戏·unity·c#·状态模式
sun_qqq11 天前
网站常用功能模块-鉴权
状态模式