是否可以验证从WSO2中的外部OAuth2服务器创建的JWT令牌?

时间:2018-12-08 20:38:09

标签: oauth-2.0 wso2 jwt wso2-am

我有一个Spring Security OAuth2服务器,它为前端应用程序生成JWT令牌。

此令牌将通过API网关(WSO2 API管理器)在调用中发送到后端。

我想要在WSO2中注册后端API,并能够验证外部生成的JWT令牌。

这可能吗?您能否提供需要配置以包含此逻辑的WSO2 APIM不同位置的示例?

注意:WSO2永远不需要创建令牌,它始终是以前创建的,只需要对其进行验证即可。

2 个答案:

答案 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>

重要提示:

  1. 处理后端通常是从OAuth2访问令牌派生的(在正常的OAuth2请求中)。由于在这里我们替换了它,WSO2无法确定要调用哪个环境,因此它将默认调用PRODUCTION。要解决此问题,在我的案例环境中,请在您的JWT中插入一些额外的字段,以帮助您做出决定。然后,如图所示,使用适当的环境创建一个AuthenticationContext。就是这样!

  2. 如果直接编辑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令牌。