oauth-2.0 在Spring引导资源服务器中使用自定义JWT解码器

jmo0nnb3  于 2022-10-31  发布在  Spring
关注(0)|答案(2)|浏览(161)

我正在使用Spring引导资源服务器。身份验证服务器发出一个JWT。此JWT使用一个密钥重新编码(使用AES),在资源服务器中,我应该在将其发送到JwtAuthenticator之前解码JWT(从AES)。
现在,我有了一个安全配置。

@Override
    protected void configure(HttpSecurity http) throws Exception {

        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new KeycloakRoleConverter());

        http
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/users/status/check")
                .hasRole("developer")
                .anyRequest().authenticated()
                .and()
                .oauth2ResourceServer()
                .jwt()
                .decoder(new JWTDecoder())
                .jwtAuthenticationConverter(jwtAuthenticationConverter);
    }

和一个JWT解码器

import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTParser;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtException;

import java.text.ParseException;

public class JWTDecoder implements JwtDecoder {
    @Override
    public Jwt decode(String token) throws JwtException {

        //decrypt from AES here

        JWT jwt = null;
        try {
            jwt = JWTParser.parse(token);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        return null;
    }
}

函数应该返回org.springframework.security.oauth2.jwt.Jwt,如何将String token转换为Jwt?
我尝试了以下操作,但出现了问题。

private Jwt createJwt(String token, JWT parsedJwt) {
        try {
            Map<String, Object> headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject());
            Map<String, Object> claims = parsedJwt.getJWTClaimsSet().getClaims();
            return Jwt.withTokenValue(token)
                    .headers(h -> h.putAll(headers))
                    .claims(c -> c.putAll(claims))
                    .build();
        } catch (Exception ex) {
            if (ex.getCause() instanceof ParseException) {
                throw new JwtException("There is a problem parsing the JWT.");
            } else {
                throw new JwtException("There is a problem decoding the JWT.");
            }
        }
    }

我收到的错误:
异常错误:时间戳的类型必须为“即时:java.lang.Long
我使用Keycloak来生成JWT。因此,www.example.com中标记的exp字段jwt.io是"exp": 1657363340,。但是在我的代码中解析JWT后,它更改为Date格式。因此,我将exp更改为Instant,最后的方法如下所示:

private Jwt createJwt(String token, JWT parsedJwt) {
        try {
            Map<String, Object> headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject());
            Map<String, Object> claims = parsedJwt.getJWTClaimsSet().getClaims();
            Jwt.Builder finalJwt = Jwt.withTokenValue(token)
                    .headers(h -> h.putAll(headers))
                    .claims(c -> c.putAll(claims));
            finalJwt.expiresAt(((Date) claims.get("exp")).toInstant());
            return finalJwt.build();
        } catch (Exception ex) {
            if (ex.getCause() instanceof ParseException) {
                throw new JwtException("There is a problem parsing the JWT: " + ex.getMessage());
            } else {
                throw new JwtException("There is a problem decoding the JWT: " + ex.getMessage());
            }
        }
    }

但问题仍然存在。

6bc51xsx

6bc51xsx1#

这可能是由于令牌的到期日期是一个时间戳,而它应该是一个数字(长整数)。或者您正在尝试将时间戳解析为长整数。

5fjcxozz

5fjcxozz2#

正如@Jose告诉我的,我用Instant类型的时间戳设置过期时间的值。然后,我将它设置为JWT的expiat字段。我的最终函数如下所示:

Map<String, Object> headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject());
Map<String, Object> claims = new HashMap<>();
for (String key : parsedJwt.getJWTClaimsSet().getClaims().keySet()) {
    Object value = parsedJwt.getJWTClaimsSet().getClaims().get(key);
    if (key.equals("exp") || key.equals("iat")) {
        value = ((Date) value).toInstant();
    }
    claims.put(key, value);
}
return Jwt.withTokenValue(token)
        .headers(h -> h.putAll(headers))
        .claims(c -> c.putAll(claims))
        .build();

相关问题