java - 可以将java与jwt、rs256和auth0一起使用吗?

标签 java spring-boot jwt

这是我在尝试验证 jwt token 时遇到的异常: RSA 公钥仅支持 RSAPublicKeySpec 和 X509EncodedKeySpec

我正在使用 com.nimbusds.jose。

这是 doFilter 方法:

    @Override
    public void doFilter(final ServletRequest req,
                         final ServletResponse res,
                         final FilterChain chain) throws IOException, ServletException {


        final HttpServletRequest request = (HttpServletRequest) req;
        if (request.getMethod().equalsIgnoreCase("OPTIONS")) {
            chain.doFilter(req, res);
        } else {

            String workingDir = System.getProperty("user.dir");
            System.out.println("Current working directory : " + workingDir);

            final String authHeader = request.getHeader("Authorization");
            if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                throw new ServletException("Missing or invalid Authorization header.");
            }

            final String token = authHeader.substring(7); // The part after "Bearer "
            try {
                JWSObject jwsObject = JWSObject.parse(token);
                JWSVerifier verifier = new RSASSAVerifier(getPublicKey("szabo.cer"));
                jwsObject.verify(verifier);
            } catch (ParseException e) {
                e.printStackTrace();
            } catch (GeneralSecurityException e) {
                e.printStackTrace();
            } catch (JOSEException e) {
                e.printStackTrace();
            }
            chain.doFilter(req, res);
        }

    }

这是完整的类代码:

package com.associations.security;

import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import org.apache.tomcat.util.codec.binary.Base64;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.text.ParseException;


/**
 * Created by admin on 16.07.2017.
 */
public class JwtFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    private static String getKey(String filename) throws IOException {
        // Read key from file
        String strKeyPEM = "";
        BufferedReader br = new BufferedReader(new FileReader(filename));
        String line;
        while ((line = br.readLine()) != null) {
            strKeyPEM += line + "\n";
        }
        br.close();
        return strKeyPEM;
    }

    public static RSAPublicKey getPublicKey(String filename) throws IOException, GeneralSecurityException {
        String publicKeyPEM = getKey(filename);
        return getPublicKeyFromString(publicKeyPEM);
    }

    public static RSAPublicKey getPublicKeyFromString(String key) throws IOException, GeneralSecurityException {
        String publicKeyPEM = key;
        publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----\n", "");
        publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");
        byte[] encoded = Base64.decodeBase64(publicKeyPEM);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(new PKCS8EncodedKeySpec(encoded));
        return pubKey;
    }

    @Override
    public void doFilter(final ServletRequest req,
                         final ServletResponse res,
                         final FilterChain chain) throws IOException, ServletException {


        final HttpServletRequest request = (HttpServletRequest) req;
        if (request.getMethod().equalsIgnoreCase("OPTIONS")) {
            chain.doFilter(req, res);
        } else {

            String workingDir = System.getProperty("user.dir");
            System.out.println("Current working directory : " + workingDir);

            final String authHeader = request.getHeader("Authorization");
            if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                throw new ServletException("Missing or invalid Authorization header.");
            }

            final String token = authHeader.substring(7); // The part after "Bearer "
            try {
                JWSObject jwsObject = JWSObject.parse(token);
                JWSVerifier verifier = new RSASSAVerifier(getPublicKey("szabo.cer"));
                jwsObject.verify(verifier);
            } catch (ParseException e) {
                e.printStackTrace();
            } catch (GeneralSecurityException e) {
                e.printStackTrace();
            } catch (JOSEException e) {
                e.printStackTrace();
            }
            chain.doFilter(req, res);
        }

    }


    public void destroy() {

    }
}

这是堆栈跟踪:

2017-07-21 09:18:39.804  INFO 8852 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2017-07-21 09:18:39.805  INFO 8852 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2017-07-21 09:18:39.822  INFO 8852 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 17 ms
Current working directory : E:\AdrianEmberTests\szabo
java.security.spec.InvalidKeySpecException: Only RSAPublicKeySpec and X509EncodedKeySpec supported for RSA public keys
    at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:306)
    at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:201)
    at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
    at com.associations.security.JwtFilter.getPublicKeyFromString(JwtFilter.java:51)
    at com.associations.security.JwtFilter.getPublicKey(JwtFilter.java:42)
    at com.associations.security.JwtFilter.doFilter(JwtFilter.java:77)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)

最佳答案

您正在使用旨在包装私钥的 PKCS8EncodedKeySpec 构建公钥

 RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(new PKCS8EncodedKeySpec(encoded));

使用这个

RSAPublicKey pubKey = (RSAPublicKey)
     KeyFactory.getInstance("RSA")
           .generatePublic(new X509EncodedKeySpec(bytes));

关于java - 可以将java与jwt、rs256和auth0一起使用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45221017/

相关文章:

php - Lumen + Dingo + JWT 在构建时不可实例化

python - 订阅 Microsoft Office 365 管理事件 API : Authorization denied

java - 在 Spring Web Flow 中格式化绑定(bind)日期字段

java - 数独生成器算法优化 欢迎

java - 如何使用 Java - Selenium 组合清除表单上的输入字段

java - 不支持POST请求方式

c# - JWT token 过期在 Asp.Net Core API 中不起作用?

java - 从数据库中计算产品时 Firebase 变慢 (Android)

spring - 为什么 Swagger 的 api-docs 响应包含在额外的 JSON 对象中?

java - 测试单元 Spring Boot : Unable to register mock bean