После долгих проб и ошибок и некоторой помощи от 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 (последний необходимо удалить из-за хорошо известной ошибки для apis без аутентификации oauth2):
Должно быть что-то вроде этого:
<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) для их выбора.
speed_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>