Java中的服务端点认证与授权:JWT与Spring Security OAuth2

大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们将深入探讨如何在Java应用中实现服务端点的认证与授权,重点关注JWT(JSON Web Token)和Spring Security OAuth2。我们将通过实际代码示例展示如何使用这两种技术来保护和管理API端点。

1. JWT(JSON Web Token)认证

1.1 引入依赖

首先,我们需要在pom.xml中添加JWT的依赖:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

1.2 JWT工具类

接下来,我们创建一个JWT工具类,用于生成和解析JWT:

package cn.juwatech.example;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;

public class JwtUtil {

    private static final String SECRET_KEY = "your-secret-key";

    public static String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60)) // 1 hour
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    public static Claims extractClaims(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
    }

    public static String getUsername(String token) {
        return extractClaims(token).getSubject();
    }

    public static boolean isTokenExpired(String token) {
        return extractClaims(token).getExpiration().before(new Date());
    }

    public static boolean validateToken(String token, String username) {
        return (username.equals(getUsername(token)) && !isTokenExpired(token));
    }
}

1.3 JWT过滤器

创建一个JWT过滤器来处理请求中的JWT:

package cn.juwatech.example;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String token = request.getHeader("Authorization");

        if (token != null && JwtUtil.validateToken(token, JwtUtil.getUsername(token))) {
            Authentication auth = new JwtAuthenticationToken(JwtUtil.getUsername(token), null, null);
            SecurityContextHolder.getContext().setAuthentication(auth);
        }

        filterChain.doFilter(request, response);
    }
}

1.4 配置Spring Security

SecurityConfig中配置Spring Security以使用JWT过滤器:

package cn.juwatech.example;

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.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

2. Spring Security OAuth2

2.1 引入依赖

添加Spring Security OAuth2的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

2.2 配置OAuth2资源服务器

application.yml中配置OAuth2资源服务器:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://your-auth-server.com/oauth2/default

2.3 配置Spring Security

配置Spring Security以使用OAuth2资源服务器:

package cn.juwatech.example;

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.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .oauth2ResourceServer()
                .jwt();
    }
}

2.4 自定义JWT解析

如果需要自定义JWT解析逻辑,可以实现JwtAuthenticationConverter

package cn.juwatech.example;

import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;

public class CustomJwtAuthenticationConverter extends JwtAuthenticationConverter {

    @Override
    protected Collection<SimpleGrantedAuthority> extractAuthorities(Jwt jwt) {
        Map<String, ?> claims = jwt.getClaims();
        // Extract roles from JWT claims
        return Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
    }
}

并在SecurityConfig中注册自定义的JwtAuthenticationConverter

@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
    CustomJwtAuthenticationConverter converter = new CustomJwtAuthenticationConverter();
    return converter;
}

3. 结论

本文通过代码示例详细介绍了如何使用JWT和Spring Security OAuth2实现Java应用的服务端点认证与授权。JWT提供了灵活的令牌管理方案,而OAuth2则为资源服务器提供了标准化的安全保障。这两种技术可以根据应用的需求来选择和配置,以确保服务端点的安全性。