【发布时间】:2021-09-23 19:52:56
【问题描述】:
我正在使用 Spring Boot 构建一个新的 API。它将暴露给外部客户(公司网络之外)。这是通过网关(apigee)完成的。
Apigee 提供了一个外部可访问的终端节点并使用 Oauth2 对其进行保护。当客户端使用有效凭据访问外部端点时,apigee 会将请求转发到我的 API 端点。 Apigee 还在标头中添加了 JWT,这将包含客户端使用的 API 密钥。在我的应用程序中 我已经定义了一个过滤器(扩展了 OncePerRequestFilter),它使用网关的公钥从 JWT 中提取 API 密钥。 我正在使用 FilterRegistrationBean 添加过滤器。
现在我在过滤器中有 api-key,我需要做两件事:
- 使用 api-key 访问内部 mySQL DB 并获取有关调用者的各种信息(将其存储在 ApiConsumer 对象中)。
- 如果在 DB 中找不到密钥,那么我想返回 401。
我在网上看到了许多使用 Spring Security 和 AuthenticationManager、UserDetailsService 等代码进行 JWT 验证的示例。 我必须做这一切吗? 由于我的过滤器中已经有了 api-key,有没有办法可以从过滤器进行 DB 调用并验证数据库中是否存在密钥? 然后我可以将值存储在 apiConsumer 中。
过滤器代码:
public class AuthFilter extends OncePerRequestFilter {
@Autowired
ApiConsumer aPiConsumer;
@Value("${jwt.pubkey}")
private String publickey;
@Value("${jwt.iss}")
private String iss;
@Value("${jwt.sub}")
private String sub;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws Exception {
String header = request.getHeader("Authorization");
if (header == null || !header.startsWith("Bearer ")) {
throw new Exception("No JWT found");
}
String jwtToken = header.substring(7);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publickey.getBytes()));
PublicKey pubKey = KeyFactory.getInstance("RSA").generatePublic(keySpec);
@SuppressWarnings("rawtypes")
final JwsHeader jwsHeader = Jwts.parser().setSigningKey(pubKey).parseClaimsJws(jwtToken).getHeader();
String jwtType = jwsHeader.getType();
String jwtAlgorithm = jwsHeader.getAlgorithm();
if (!((jwtType.equals("JWT")) && (jwtAlgorithm.equals("RS256")))) {
throw new Exception("Invalid JWT Type or Algorithm");
}
final Claims claims = Jwts.parser().setSigningKey(pubKey).parseClaimsJws(jwtToken).getBody();
String issuer = claims.getIssuer();
String subject = claims.getSubject();
String apiKey = claims.get("apikey", String.class);
if (!((issuer.equals(iss)) && (subject.equals(sub)))) {
throw new Exception("Invalid JWT Issuer or Subject");
} else {
aPiConsumer.setApiKey(apikey);
//I have the api key. Now need to hit MySQL database to access this.
}
filterChain.doFilter(request, response);
}
}
bean 代码:
@Configuration
public class AuthConfig {
@Bean
public FilterRegistrationBean authorizationFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(authFilter());
registration.setName("authFilter");
return registration;
}
@Bean
public Filter authFilter() {
return new AuthFilter();
}
}
【问题讨论】:
-
你为什么不使用内置的 Spring Security 支持来为你做这一切?
标签: java spring spring-boot jwt