我有一个Spring Security OAuth2服务器,它为前端应用程序生成JWT令牌。
此令牌将通过API网关(WSO2 API管理器)在调用中发送到后端。
我想要在WSO2中注册后端API,并能够验证外部生成的JWT令牌。
这可能吗?您能否提供需要配置以包含此逻辑的WSO2 APIM不同位置的示例?
注意:WSO2永远不需要创建令牌,它始终是以前创建的,只需要对其进行验证即可。
答案 0 :(得分:2)
经过大量的反复试验和Stackoverflow的一些帮助(对Bee表示敬意),这是我的可行解决方案。我希望它能对其他人有所帮助,因为使其工作起来确实很棘手:
1。实现JWTAuthHandler以验证JWT令牌:
public class JwtAuthHandler extends AbstractHandler {
private final PublicKeyFactory pkf = new PublicKeyFactory();
private final JwtVerifier jwtVerifier = new JwtVerifier();
@Override
public boolean handleRequest(MessageContext messageContext) {
try {
final String jwtToken = getJwtTokenFromHeaders(messageContext).replace("Bearer ", "");
SignedJWT signedJwt = SignedJWT.parse(jwtToken);
final JSONObject payload = signedJwt.getPayload().toJSONObject();
final JSONObject environment = (JSONObject)payload.get("environment");
PublicKey publicKey = readPublicKey();
JWSVerifier verifier = new RSASSAVerifier(((RSAPublicKey) publicKey));
final boolean signatureVerification = signedJwt.verify(verifier)
if (signatureVerification) {
AuthenticationContext authContext = new AuthenticationContext();
authContext.setAuthenticated(true);
if (isProductionRequest(environment)) {
authContext.setKeyType(APIConstants.API_KEY_TYPE_PRODUCTION);
} else {
authContext.setKeyType(APIConstants.API_KEY_TYPE_SANDBOX);
}
APISecurityUtils.setAuthenticationContext(messageContext, authContext, "Authorization");
} else {
LOG.debug("handleRequest() - Sending 401 Unauthorized");
Utils.sendFault(messageContext, 401);
}
return signatureVerification;
} catch (Exception e) {
e.printStackTrace();
Utils.sendFault(messageContext, 500);
return false;
}
}
@Override
public boolean handleResponse(MessageContext messageContext) {
return true;
}
private String getJwtTokenFromHeaders(MessageContext messageContext) {
Map headers = (Map) ((Axis2MessageContext) messageContext).getAxis2MessageContext().
getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
return (String) headers.get("Authorization");
}
private boolean isProductionRequest(JSONObject environment) {
return environment != null && environment.equals("pro");
}
}
2。覆盖您的API定义(/repository/deployment/server/synapse-configs/default/api/yourapi.xml
)以使用jwt处理程序并删除APIAuthenticationHandler和ThrottleHandler(由于非oauth2-authenticated api的一个众所周知的错误,因此需要删除ThrottleHandler): < / p>
它应该是这样的:
<handlers>
<handler class="com.codependent.JwtAuthHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.common.APIMgtLatencyStatsHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.CORSRequestHandler">
<property name="apiImplementationType" value="ENDPOINT"/>
</handler>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.analytics.APIMgtUsageHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.analytics.APIMgtGoogleAnalyticsTrackingHandler">
<property name="configKey" value="gov:/apimgt/statistics/ga-config.xml"/>
</handler>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerExtensionHandler"/>
</handlers>
重要提示:
处理后端通常是从OAuth2访问令牌派生的(在正常的OAuth2请求中)。由于在这里我们替换了它,WSO2无法确定要调用哪个环境,因此它将默认调用PRODUCTION。要解决此问题,在我的案例环境中,请在您的JWT中插入一些额外的字段,以帮助您做出决定。然后,如图所示,使用适当的环境创建一个AuthenticationContext
。就是这样!
如果直接编辑yourapi.xml描述符,则下次发布时将替换它。要自动生成,请编辑速度模板(/repository/resources/api_templates/velocity_template.xml
)。就我而言,我只希望它适用于某些应用程序,因此我使用标签(jwt-auth)来选择它们。
velocity_template.xml:
<handlers xmlns="http://ws.apache.org/ns/synapse">
#if($apiObj.tags.contains("jwt-auth"))
<handler class="com.codependent.JwtAuthHandler"/>
#end
#foreach($handler in $handlers)
#if((($handler.className != "org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler") &&
($handler.className != "org.wso2.carbon.apimgt.gateway.handlers.throttling.ThrottleHandler")) ||
!($apiObj.tags.contains("jwt-auth")))
<handler xmlns="http://ws.apache.org/ns/synapse" class="$handler.className">
#if($handler.hasProperties())
#set ($map = $handler.getProperties() )
#foreach($property in $map.entrySet())
<property name="$!property.key" value="$!property.value"/>
#end
#end
</handler>
#end
#end
</handlers>
答案 1 :(得分:0)
实际上,您可以编写一个自定义处理程序来自行进行身份验证(基本身份验证,jwt承载)。很快找到好工作。也许作为一项改进,您可以缓存已验证的jwt令牌(或jwt哈希),因为验证可能需要一些时间和性能。
作为默认解决方案(无任何自定义),您可以使用JWT grant 将来自可信IdP的令牌交换为内部APIM令牌。