JAVA WebAPI中的Token认证与数字签名实现

Token认证的基本原理

Token认证是一种无状态的认证机制,客户端在首次登录后获取一个Token,后续请求携带该Token进行身份验证。常见的Token类型包括JWT(JSON Web Token)。

JWT由三部分组成:Header、Payload和Signature,使用Base64URL编码后拼接而成。Header包含算法和类型信息,Payload包含用户数据,Signature用于验证Token的完整性。

JWT Token生成与验证

生成JWT Token需要使用密钥和指定算法(如HS256)。以下代码示例展示如何生成和验证JWT:

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.security.Keys;
import java.security.Key;

public class JwtUtil {
    private static final Key SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);

    public static String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .signWith(SECRET_KEY)
                .compact();
    }

    public static Claims validateToken(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(SECRET_KEY)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }
}

数字签名的工作原理

数字签名用于验证数据的完整性和来源真实性。发送方使用私钥对数据进行签名,接收方使用公钥验证签名。常见的算法包括RSA和ECDSA。

以下代码示例展示如何使用Java的Signature类进行数字签名:

import java.security.*;
import java.util.Base64;

public class DigitalSignature {
    public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        return keyGen.generateKeyPair();
    }

    public static String sign(String data, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data.getBytes());
        byte[] digitalSignature = signature.sign();
        return Base64.getEncoder().encodeToString(digitalSignature);
    }

    public static boolean verify(String data, String signature, PublicKey publicKey) throws Exception {
        Signature sig = Signature.getInstance("SHA256withRSA");
        sig.initVerify(publicKey);
        sig.update(data.getBytes());
        return sig.verify(Base64.getDecoder().decode(signature));
    }
}

WebAPI中的Token认证实现

在Spring Boot应用中,可以通过过滤器实现Token认证。以下示例展示如何创建JWT认证过滤器:

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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 token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
            try {
                Claims claims = JwtUtil.validateToken(token);
                UsernamePasswordAuthenticationToken authentication = 
                    new UsernamePasswordAuthenticationToken(claims.getSubject(), null, null);
                SecurityContextHolder.getContext().setAuthentication(authentication);
            } catch (Exception e) {
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid token");
                return;
            }
        }
        filterChain.doFilter(request, response);
    }
}

结合数字签名的Token增强

为了提高Token的安全性,可以结合数字签名技术。以下示例展示如何生成带有数字签名的Token:

public class SignedJwt {
    private static KeyPair keyPair;

    static {
        try {
            keyPair = DigitalSignature.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Failed to generate key pair", e);
        }
    }

    public static String generateSignedToken(String username) throws Exception {
        String jwt = JwtUtil.generateToken(username);
        String signature = DigitalSignature.sign(jwt, keyPair.getPrivate());
        return jwt + "." + signature;
    }

    public static boolean verifySignedToken(String signedToken) throws Exception {
        String[] parts = signedToken.split("\\.");
        if (parts.length != 2) return false;
        
        String jwt = parts[0];
        String signature = parts[1];
        return DigitalSignature.verify(jwt, signature, keyPair.getPublic());
    }
}

实际应用中的安全考虑

Token应设置合理的过期时间,防止长期有效带来的安全风险。敏感操作应要求重新认证,即使Token仍然有效。

数字签名使用的私钥必须妥善保管,建议使用硬件安全模块(HSM)或密钥管理服务。公钥可以安全地分发给需要验证签名的客户端。

// 设置Token过期时间示例
public static String generateTokenWithExpiration(String username, long expirationMs) {
    return Jwts.builder()
            .setSubject(username)
            .setExpiration(new Date(System.currentTimeMillis() + expirationMs))
            .signWith(SECRET_KEY)
            .compact();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值