为JWT令牌验证假设客户端自定义拦截器

时间:2018-02-08 13:56:09

标签: spring-cloud-feign feign

我是新来的春天,假装和探索几天。 我能够对我们的受保护资源(用户名/密码)进行身份验证请求,并在后续请求标头中使用auth服务返回的JWT令牌。 但是,我想在令牌过期时使用相同的凭证来调用auth服务.Spring云有OAuth2FeignRequestInterceptor,它使用客户端ID和密钥完全相同。

用于处理用户名和密码生成的令牌的任何此类自定义拦截器?

3 个答案:

答案 0 :(得分:1)

如果您的JWT令牌提供程序符合OAuth 2.0,则可以使用OAuth2FeignRequestInterceptor对象配置OAuth2ProtectedResourceDetails。此对象是所有OAuth 2.0授权类型信息的基类。在您的情况下,我建议使用ResourceOwnerPasswordResourceDetails代替。这将允许您使用用户名和密码配置拦截器。

@Configuration
public class OAuth2RequestInterceptorConfiguration {

    @Bean
    public OAuth2FeignRequestInterceptor requestInterceptor() {
        OAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
        OAuth2ProtectedResourceDetails resourceDetails =
            new ResourceOwnerPasswordResourceDetails();
        resourceDetails.setUsername("username");
        resourceDetails.setPassword("password");
        return new OAuth2FeignRequestInterceptor(clientContext, resourceDetails);
    }
}

对于其他情况,您需要创建自己的RequestInterceptor

public class MyRequestInterceptor implements RequestInterceptor {

    private String jwt;
    private LocalDateTime expirationDate;

    @Override
    public void apply(RequestTemplate requestTemplate) {
        /* validate and refresh your token, this sample is not thread safe */
        if (LocalDateTime.now().isAfter(expirationDate)) {
            requestToken();
        }

        /* use the token */
        requestTemplate.header("Authorization: Bearer " + this.jwt);
    }
}

答案 1 :(得分:0)

用例并不完全清楚,但也许下面的代码片段也很有用。我们的服务需要签名的OAuth Bearer JWT 访问令牌。您可以看到我们在JWT到期时明确验证,并且当JWT令牌过期时我们会返回错误。在我们的设置中,消费者有责任在发生此情况时捕获此错误并使用刷新令牌(以检索新的访问令牌)。

希望这有点澄清。

维姆

/**
 * Created by Wim Van den Brande on 11/02/2018.
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger LOGGER = LoggerFactory.getLogger(SecurityConfig.class);

    public static final String SCOPE = "scope";
    public static final String HEADER_AUTHORIZATION = "Authorization";
    public static final String HEADER_BEARER = "Bearer";
    public static final String HEADER_ENCRYPTION_TYPE = "Encryption-Type";
    public static final String ASSYMETRIC_ENCRYPTION_RS256 = "RS256";

    @Value("${CS.signedPublicKey}")
    private String signedPublicKey;

    @Autowired
    private Key signinKey;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // TODO : to enable CSRF
        http.httpBasic().and().csrf().disable();

        TokenAuthenticationFilter tokenFilter = new TokenAuthenticationFilter();
        http.addFilterBefore(tokenFilter, BasicAuthenticationFilter.class);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/admin", "/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**");
    }

    // Actual Implementation of Token Based Authentication
    // ---------------------------------------------------
    public class TokenAuthenticationFilter extends GenericFilterBean {

        @Override
        public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
            final HttpServletRequest httpRequest = (HttpServletRequest) request;
            final HttpServletResponse httpResponse = (HttpServletResponse) response;

            String authorizationHeader = httpRequest.getHeader(HEADER_AUTHORIZATION);

            if (authorizationHeader == null) {
                    httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, String.format("Request doesn't contain header %s.", HEADER_AUTHORIZATION));
                    return;
            }

            String[] authorizationHeaderValues = authorizationHeader.split("\\s+");

            if (authorizationHeaderValues.length != 2 || !authorizationHeaderValues[0].equals(HEADER_BEARER)) {
                httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, String.format("AuthorizationHeader %s is an invalid header ", authorizationHeader));
                return;
            }

            String accessToken = authorizationHeaderValues[1];
            Claims jwtClaims;

            // Symmetric Encryption is our default

            if (httpRequest.getHeader(HEADER_ENCRYPTION_TYPE) == null || !httpRequest.getHeader(HEADER_ENCRYPTION_TYPE).equals(ASSYMETRIC_ENCRYPTION_RS256)) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Using Symmetric algorithm");
                }

                try {
                    jwtClaims = Jwts.parser().setSigningKey(signinKey).parseClaimsJws(accessToken).getBody();
                }
                catch (ExpiredJwtException e) {
                    httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "JSON Web Token has expired");
                    return;
                }
            }

在这里输入代码

答案 2 :(得分:0)

您可以尝试以下操作:

public class FeignConfiguration {

    @Value("${security.jwt.token}")
    private String jwtToken;

    @Bean
    public RequestInterceptor requestInterceptor() {
        @Override
        public void apply(RequestTemplate requestTemplate) {
            requestTemplate.header("Authorization", jwtToken);
        }
    }
}