Springboot Security + JWT 请求验证

配置

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。包括用户认证和用户授权,在使用Session的认证中,security取出session中的信息进行验证。使用了JWT,禁用session,需要在security之前加上filter,在filter中验证token然后把用户信息和session一样填入SecurityContext中。

禁用session

                // 基于token,所以不需要session
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

在securityconfig中加入filter

        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

filter中验证token

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private UserService userDetailsService;
    @Autowired
    private JWTUtil jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String token = request.getHeader(jwtTokenUtil.getHeader());
        String username = jwtTokenUtil.getUsernameFromToken(token);

        logger.info(String.format("Checking authentication for user %s.", username));

        if (!StringUtils.isEmpty(token)) {
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null){
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                if (jwtTokenUtil.validateToken(token, userDetails)){
                    // 将用户信息存入 authentication,方便后续校验
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    // 将 authentication 存入 ThreadLocal,方便后续获取用户信息
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }
        chain.doFilter(request, response);
    }
}

使用JWT的好处:

1. 可扩展性好

应用程序分布式部署的情况下,session需要做多机数据共享,通常可以存在数据库或者redis里面。而jwt不需要。

2. 无状态,降低耦合度

jwt不在服务端存储任何状态。RESTful API的原则之一是无状态,发出请求时,总会返回带有参数的响应,不会产生附加影响。用户的认证状态引入这种附加影响,这破坏了这一原则。另外jwt的载荷中可以存储一些常用信息,用于交换信息,有效地使用 JWT,可以降低服务器查询数据库的次数。

 

 

 

### Spring Boot Security JWT Token Integration Tutorial #### 1. 添加必要的依赖项 为了实现基于JWT的安全机制,在`pom.xml`文件中除了常规的Spring Boot Starter外,还需要加入安全模块以及JSON Web Tokens的支持。 ```xml <dependencies> <!-- Spring Boot Starter Security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- JSON Web Token Support --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.2</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred --> <version>0.11.2</version> <scope>runtime</scope> </dependency> </dependencies> ``` 上述配置引入了用于创建和验证JWT令牌所需的库[^2]。 #### 2. 配置Security设置 通过自定义`WebSecurityConfigurerAdapter`类来调整默认的安全策略。这一步骤涉及定义哪些URL路径应该受到保护,并指定登录逻辑处理方式。 ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/authenticate").permitAll() // Allow everyone to access the authentication endpoint. .anyRequest().authenticated(); // All other requests require authentication. // Add custom filter for processing tokens before reaching controllers. http.addFilterBefore(new JwtRequestFilter(), UsernamePasswordAuthenticationFilter.class); } } ``` 此部分代码禁用了CSRF防护并设置了基本的身份验证规则,允许未授权访问特定端点(如身份验证API),而其他请求则需经过身份验证才能继续执行[^3]。 #### 3. 创建Token服务 构建一个简单的接口用来生成新的JWT实例;通常情况下会包含用户的唯一标识符作为载荷的一部分。 ```java @Service public class JwtUtil { private String secret = "your_secret_key"; public String generateToken(UserDetails userDetails){ Map<String, Object> claims = new HashMap<>(); return Jwts.builder() .setClaims(claims) .setSubject(userDetails.getUsername()) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // Expire after 10 hours. .signWith(SignatureAlgorithm.HS512, secret).compact(); } public Boolean validateToken(String token, UserDetails userDetails){ final String username = getUsernameFromToken(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } private String getUsernameFromToken(String token){ return getAllClaimsFromToken(token).getSubject(); } private Claims getAllClaimsFromToken(String token){ return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } private Boolean isTokenExpired(String token){ final Date expiration = getExpirationDateFromToken(token); return expiration.before(new Date()); } private Date getExpirationDateFromToken(String token){ return getAllClaimsFromToken(token).getExpiration(); } } ``` 这段Java程序展示了如何利用`JJWT`库中的工具方法来编码/解码token字符串,并提供了几个辅助函数来进行签名验证和其他操作[^4]。 #### 4. 实现过滤器以解析传入HTTP头内的Bearer Token 编写一个实现了`OncePerRequestFilter`接口的新组件,它会在每次收到客户端发送过来的数据包之前自动触发,从而可以从中提取出携带者凭证信息并尝试完成用户身份确认过程。 ```java @Component public class JwtRequestFilter extends OncePerRequestFilter { @Autowired private MyUserDetailsService userDetailsService; @Autowired private JwtUtil jwtUtil; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException{ final String authorizationHeader = request.getHeader("Authorization"); String username = null; String jwt = null; if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { jwt = authorizationHeader.substring(7); try { username = jwtUtil.getUsernameFromToken(jwt); } catch(IllegalArgumentException e){ System.out.println("Unable to get JWT Token"); }catch(JwtException e){ System.out.println("JWT token is expired or invalid"); } }else{ logger.warn("couldn't find bearer string, will ignore the header"); } if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); if (jwtUtil.validateToken(jwt, userDetails)){ UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken( userDetails,null,userDetails.getAuthorities()); authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authToken); } } chain.doFilter(request,response); } } ``` 该片段说明了一个典型的拦截链路设计模式的应用场景——即每当有新连接建立时都会先调用此类对象的方法去检查是否存在有效的认证凭据,如果存在,则更新当前线程关联的安全上下文环境以便后续业务层能够获取到已知的身份详情记录[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值