簡體   English   中英

為什么我在嘗試構建 JWT 令牌時遇到此異常? java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter

[英]Why am I obtaining this exception trying to build a JWT token? java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter

我正在研究實現 JWT 身份驗證的 Spring 引導項目,但我發現了一些困難。 它基於在 Udemy 課程中發現的一個示例,我正試圖適應我的特定用例。 它由以下兩個微服務組成:

  1. GET-USER-WS:這是從數據庫中獲取用戶信息的微服務。

  2. AuthServerJWT:此微服務調用GET-USER-WS以獲取用戶信息並構建將由其他微服務使用的 JWT 令牌。

基本上,第二個AuthServerJWT包含以下JwtAuthenticationRestController controller class:

@RestController
//@CrossOrigin(origins = "http://localhost:4200")
public class JwtAuthenticationRestController  {

    @Value("${sicurezza.header}")
    private String tokenHeader;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    @Qualifier("customUserDetailsService")
    private UserDetailsService userDetailsService;
    
    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationRestController.class);

    @PostMapping(value = "${sicurezza.uri}")
    public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtTokenRequest authenticationRequest)
            throws AuthenticationException {
        logger.info("Autenticazione e Generazione Token");

        authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword());

        final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername());

        final String token = jwtTokenUtil.generateToken(userDetails);
        
        logger.warn(String.format("Token %s", token));

        return ResponseEntity.ok(new JwtTokenResponse(token));
    }

    @RequestMapping(value = "${sicurezza.uri}", method = RequestMethod.GET)
    public ResponseEntity<?> refreshAndGetAuthenticationToken(HttpServletRequest request) 
            throws Exception 
    {
        String authToken = request.getHeader(tokenHeader);
        
        if (authToken == null || authToken.length() < 7)
        {
            throw new Exception("Token assente o non valido!");
        }
        
        final String token = authToken.substring(7);
        
        if (jwtTokenUtil.canTokenBeRefreshed(token)) 
        {
            String refreshedToken = jwtTokenUtil.refreshToken(token);
            
            return ResponseEntity.ok(new JwtTokenResponse(refreshedToken));
        } 
        else 
        {
            return ResponseEntity.badRequest().body(null);
        }
    }

    @ExceptionHandler({ AuthenticationException.class })
    public ResponseEntity<String> handleAuthenticationException(AuthenticationException e) 
    {
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage());
    }

    private void authenticate(String username, String password) 
    {
        Objects.requireNonNull(username);
        Objects.requireNonNull(password);

        try {   
            /// ???
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        } 
        catch (DisabledException e) 
        {
            logger.warn("UTENTE DISABILITATO");
            throw new AuthenticationException("UTENTE DISABILITATO", e);
        } 
        catch (BadCredentialsException e) 
        {
            logger.warn("CREDENZIALI NON VALIDE");
            throw new AuthenticationException("CREDENZIALI NON VALIDE", e);
        }
    }
}

如您所見,它包含兩種方法:一種是創建全新的 JWT 令牌,另一種是刷新現有的 JWT 令牌。 考慮用於創建新令牌的createAuthenticationToken()

在這一行:

final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername());

它調用在我的CustomUserDetailsService中定義的loadUserByUsername()方法。 這個方法基本上是調用** GET-USER-WS的一個服務來檢索用戶信息,並建立一個UserDetails object(即一個Spring安全object),這個: userdetails.spring.frameworkDetail.core.userdetails.spring.framework

這是此方法的代碼:

@Override
public UserDetails loadUserByUsername(String UserId) throws UsernameNotFoundException {
    
    String ErrMsg = "";
    
    if (UserId == null || UserId.length() < 2) {
        ErrMsg = "Nome utente assente o non valido";
        
        logger.warn(ErrMsg);
        
        throw new UsernameNotFoundException(ErrMsg); 
    } 
    
    User user = this.GetHttpValue(UserId);
    
    if (user == null) {
        ErrMsg = String.format("User %s not found!!", UserId);
        
        logger.warn(ErrMsg);
        
        throw new UsernameNotFoundException(ErrMsg);
    }
    
    UserBuilder builder = null;
    
    builder = org.springframework.security.core.userdetails.User.withUsername(Integer.toString(user.getId()));
    builder.password(user.getPswd());
    
    String[] operations = user.getUserTypes().stream()
            .map(UserType::getOperations)
            .flatMap(Set::stream)
            .map(Operation::getName)
            .distinct()
            .toArray(String[]::new);
    
    builder.authorities(operations);
    
    
    return builder.build();
    
}

此行僅執行GetHttpValue()方法,該方法用於使用 RestTemplate 執行調用,以檢索包含用戶詳細信息的User object:

User user = this.GetHttpValue(UserId);

所以,回到前面的JwtAuthenticationRestController controller class的第一個createAuthenticationToken() 我的問題是它在這一行檢索了這個UserDetails userDetails object:

final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername());

使用調試器這是我的userDetails實例的內容:

org.springframework.security.core.userdetails.User [Username=50, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ADMIN]]

在我看來是正確的(除了包含用戶 ID 而不是用戶名的用戶名字段......我將在第二次更改,這應該不是問題)。

然后它執行此行以便從這個userDetails object 開始生成 JWT 令牌:

final String token = jwtTokenUtil.generateToken(userDetails);

這是定義在名為JwtTokenUtil的 class 中的generateToken()方法的代碼:

public String generateToken(UserDetails userDetails) {
    Map<String, Object> claims = new HashMap<>();
    return doGenerateToken(claims, userDetails);
}

它首先創建一個空的 HashMap 然后調用doGenerateToken() ,這是代碼:

private String doGenerateToken(Map<String, Object> claims, UserDetails userDetails) {
    final Date createdDate = clock.now();
    final Date expirationDate = calculateExpirationDate(createdDate);

    return Jwts.builder()
            .setClaims(claims)
            .setSubject(userDetails.getUsername())
            .claim("authorities", userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
            .setIssuedAt(createdDate)
            .setExpiration(expirationDate)
            .signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret().getBytes())
            .compact();
}

它正確地創建了expireDate日期。 然后在最后它拋出以下異常(使用調試器在我看來它是在compact()執行時拋出的):問題是當執行此行時,我得到以下異常:

java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter
    at io.jsonwebtoken.impl.Base64Codec.encode(Base64Codec.java:21) ~[jjwt-0.9.1.jar:0.9.1]
    at io.jsonwebtoken.impl.Base64UrlCodec.encode(Base64UrlCodec.java:22) ~[jjwt-0.9.1.jar:0.9.1]
    at io.jsonwebtoken.impl.DefaultJwtBuilder.base64UrlEncode(DefaultJwtBuilder.java:349) ~[jjwt-0.9.1.jar:0.9.1]
    at io.jsonwebtoken.impl.DefaultJwtBuilder.compact(DefaultJwtBuilder.java:295) ~[jjwt-0.9.1.jar:0.9.1]
    at com.easydefi.authserverjwt.security.JwtTokenUtil.doGenerateToken(JwtTokenUtil.java:87) ~[classes/:na]
    at com.easydefi.authserverjwt.security.JwtTokenUtil.generateToken(JwtTokenUtil.java:72) ~[classes/:na]
    at com.easydefi.authserverjwt.controller.JwtAuthenticationRestController.createAuthenticationToken(JwtAuthenticationRestController.java:60) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.12.jar:5.3.12]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.12.jar:5.3.12]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.12.jar:5.3.12]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.12.jar:5.3.12]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.12.jar:5.3.12]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.12.jar:5.3.12]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) ~[spring-webmvc-5.3.12.jar:5.3.12]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.12.jar:5.3.12]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.12.jar:5.3.12]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.12.jar:5.3.12]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[tomcat-embed-core-9.0.54.jar:4.0.FR]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.12.jar:5.3.12]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.54.jar:4.0.FR]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.54.jar:9.0.54]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:204) ~[spring-security-web-5.5.3.jar:5.5.3]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) ~[spring-security-web-5.5.3.jar:5.5.3]
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358) ~[spring-web-5.3.12.jar:5.3.12]
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271) ~[spring-web-5.3.12.jar:5.3.12]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.12.jar:5.3.12]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.12.jar:5.3.12]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.12.jar:5.3.12]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.12.jar:5.3.12]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.12.jar:5.3.12]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.12.jar:5.3.12]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.54.jar:9.0.54]
    at java.base/java.lang.Thread.run(Thread.java:831) ~[na:na]

為什么? 我錯過了什么? 我該如何嘗試解決這個問題?

我不知道為什么我會遇到這個問題,當我在 postgres 中運行代碼時它工作正常,但是我收到 cassandra 的錯誤。

我剛剛將這些添加到我的 pom.xml

<dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.2.7</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.2.5-b10</version>
    </dependency>

我從這里得到它們: 使用 Maven 包括 JAXB

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM