更新时间:2024-07-01 GMT+08:00
分享

企业API使用

场景简介

OneAccess提供第三方API的授权管理功能,API提供者将API配置到OneAccess之后,API消费者在使用API之前需要先到OneAccess获取鉴权Token,在使用API时携带该鉴权Token,API提供者根据鉴权Token判断是否可以提供服务,用以实现API的授权管理功能。

图1 场景简介图

前提条件

请确保您已拥有OneAccess管理门户的访问权限。

在OneAccess中添加企业应用

在OneAccess管理门户中添加企业应用,提供给API使用者获取鉴权Token信息。

  1. 登录OneAccess管理门户。
  2. 在导航栏中,单击“资源 > 应用”。
  3. 在企业应用页面,单击自建应用下的“添加自建应用”,设置Logo和名称,单击“保存”。
  4. 获取的ClientId和ClientSecret。

    在应用信息页面单击应用图标,在应用详情页面获取ClientId和ClientSecret(此信息需要提供给API使用者)。

    • ClientSecret需单击“启用”生成。
    • ClientSecret是校验开发者身份的密码,具备高安全性,切勿将其直接提供给第三方开发者或直接存储在代码中。
    • 重置后的ClientSecret即时生效,所有使用原ClientSecret的接口将全部失效,请谨慎重置。
    • OneAccess不存储ClientSecret,当获取ClientSecret后,请妥善保管。

在OneAccess中添加企业API

OneAccess管理员在OneAccess管理门户中添加企业需要的自定义API产品。

  1. 登录OneAccess管理门户。
  2. 在导航栏中,单击“资源 > 企业API”。
  3. 在企业API页面,单击自定义API产品下的“添加自定义API产品”。
  4. 在“添加企业API”页面,上传产品LOGO,填写产品名称和描述,单击“确定”,自定义API产品添加完成,自定义API产品页面显示已添加的API产品。
  5. 单击新建的自定义API产品,切换到“应用授权”页签,单击在OneAccess中添加企业应用中新建的应用后的“授权”,完成API对应用的授权使用。
  6. 切换到“权限信息”页面,添加API权限信息。

在OneAccess应用中授权相应API权限

在OneAccess的应用中,授权具体自定义API的权限。

  1. 登录OneAccess管理门户。
  2. 在导航栏中,单击“资源 > 应用”。
  3. 单击在OneAccess中添加企业应用中新建的应用,单击应用图标,进入通用信息页面。
  4. 选择“API权限 ”,在API权限页面,单击某一权限代码右侧“操作”列的“授权”则授权成功。

在OneAccess中获取签名公钥和算法密钥

OneAccess颁发的鉴权Token是经过加密和签发的,需要获取签名公钥和算法密钥给API提供者进行解密。

  1. 登录OneAccess管理门户。
  2. 在导航栏中,选择“设置 > 服务配置”,单击“API认证配置”,获取签名公钥和算法密钥,提供给APPI提供者。

    OneAccess不展示算法密钥,当重置算法密钥后,请妥善保管。

API使用者从OneAccess获取鉴权Token

API使用者调用OneAccess鉴权接口获取鉴权Token。

访问接口:https://访问域名/api/v2/tenant/token?grant_type=client_credentials。

PostMan调用示例:

  • 访问域名获取可参考获取用户访问域名
  • 使用POST访问,使用Basic认证,Basic认证的用户名和密码为4中获取的ClientId和ClientSecret。
  • 返回的id_token可以由API使用者使用对应API时传递给API提供者做身份认证和授权,其中包含签名信息以及对应的API权限信息。可以使用header来传递。建议使用标准的Authorization Header传递。
  • 返回的id_token有有效期,有效期之内,此id_token可以重复使用,有效期的期限由应用中配置决定。

API提供者校验Token

API使用者调用API提供者的接口时,携带从OneAccess获取的id_token,API提供者在收到API使用者的消息时需要校验该Token,主要校验两个内容:

  • Token的签名信息是否正确,保证Token是OneAccess颁发的。
  • 校验Token中申明的权限是否包含当前访问当前的API。

下面是java示例代码:

展开源码

import com.alibaba.fastjson.JSON;
import lombok.Data;
import org.apache.commons.codec.binary.Base64;
import org.jose4j.jwa.AlgorithmConstraints;
import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers;
import org.jose4j.jwe.JsonWebEncryption;
import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers;
import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.InvalidJwtException;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.jose4j.lang.JoseException;
 
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
 * @author : bsong
 **/
public class JWTTest {
    public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
    public static final String END_CERT = "-----END CERTIFICATE-----";
 
    public static void main(String[] args) throws CertificateException, InvalidJwtException, JoseException {
        //id token由API调用者传递
        String idToken = "";
        // 算法密钥在OneAccess中设置
        String aesKey = "0123******************************************789abc";
        //证书在OneAccess管理门户配置中获取
        String certificate = "-----BEGIN CERTIFICATE-----\n" +
                "MIIC2jCCAcKgAwI..........................QEBCwUAMC4xLDAqBgNVBAMM\n" +
                "I2Jzb25nLmlkYWF..........................GUuY29tMB4XDTIyMDExNDA3\n" +
                "MDY1NVoXDTMyMDE..........................wwjYnNvbmcuaWRhYXMtdGVz\n" +
                "dC1hbHBoYS5iY2N..........................Ib3DQEBAQUAA4IBDwAwggEK\n" +
                "AoIBAQCJ7bfMCVX..........................GnE3W9uiSYk3WFkYFK8vh16\n" +
                "efVuvccAULE+xqi..........................652lsIBNOAC5YPy7J47z4iw\n" +
                "1GiAVYXxwyehgRe3..........................e0eJDKy6Ew5S+TUq72hqSD7\n" +
                "zrtQA3szqSK1pgFB..........................J8rMh9WiF2qUqzCdNRqkQRC\n" +
                "smGGj+PqD86otiif.........................0OPH5UOhR2OEve1cT9dgAlS\n" +
                "Vt1tKbE0l+iUTQqi..........................oZIhvcNAQELBQADggEBAEP8\n" +
                "EmkyoaWjngk3Tn5u..........................cJEDGTbuYO55wKap0BTetu6\n" +
                "cvGFxJYMQYefsx0..........................xn8N4ZgWvwgwDQVQx5WPgAT\n" +
                "QKunLWz30W4GYUE..........................QJZ7ift2sqoBLmkmjfcyqW0\n" +
                "jU1+7/e/ea5XAC3..........................DtVHqufwP4R/TALg1muaNyJ\n" +
                "f7obOcMHAb/OcbP..........................FSAwkVYsxSC9LEEUPhCONvX\n" +
                "KCWoeQoX/qkZH/nBvXU=\n" +
                "-----END CERTIFICATE-----";
 
        RSAPublicKey publicKey = getPublicKeyByCertificate(certificate);
        JsonWebKey jsonWebKey = getJsonWebKey(aesKey);
        JwtClaims jwtClaims = validateIDToken(publicKey, idToken);
        String apiPermission = jwtClaims.getClaimValue("api").toString();
        String permissionString = decryptionIDToken(jsonWebKey, apiPermission);
        System.out.println(permissionString);
        Map<String, List<String>> permissions = getPermissionsFromIdToken(permissionString);
        System.out.println(permissions);
    }
 
    public static Map<String, List<String>> getPermissionsFromIdToken(String permissionString) throws JoseException {
        Map<String, List<String>> result = new HashMap<>();
        Permission permission = JSON.parseObject(permissionString,Permission.class);
        permission.getAuz().stream().forEach(p ->{
            p.entrySet().forEach(e->{
                result.put(e.getKey(),e.getValue());
            });
        });
        return result;
    }
 
    @Data
    public static class Permission{
        List<Map<String, List<String>>> auth_method;
        List<Map<String, List<String>>> auz;
    }
 
    public static RSAPublicKey getPublicKeyByCertificate(String certificate) throws CertificateException {
        CertificateFactory fact = CertificateFactory.getInstance("X.509");
        byte[] decoded = Base64.decodeBase64(certificate.replace(BEGIN_CERT, "").replace(END_CERT, ""));
        InputStream input = new ByteArrayInputStream(decoded);
        X509Certificate cert = (X509Certificate) fact.generateCertificate(input);
        return (RSAPublicKey) cert.getPublicKey();
    }
 
    public static JsonWebKey getJsonWebKey(String key) throws JoseException {
        Map<String,Object> map = new HashMap<>();
        map.put("kty","oct");
        map.put("k",key);
        String jwkJson = JSON.toJSONString(map);
        return JsonWebKey.Factory.newJwk(jwkJson);
    }
 
    public static JwtClaims validateIDToken( RSAPublicKey publicKey,String idToken) throws InvalidJwtException {
        JwtConsumer jwtConsumer = new JwtConsumerBuilder()
                .setRequireExpirationTime()                 // JWT必须具有到期时间
                .setAllowedClockSkewInSeconds(300)           //允许在验证基于时间的声明时留有余地以解决时钟偏移
                .setRequireSubject()                        // JWT必须具有主题声明
                .setExpectedIssuer("Issuer")                //谁JWT需要已被发出
                .setExpectedAudience("Audience")            // JWT的目标对象
                .setVerificationKey(publicKey)
                .build();
        return jwtConsumer.processToClaims(idToken);
    }
 
    public static String decryptionIDToken(JsonWebKey jwk, String idToken) throws JoseException {
        JsonWebEncryption jsonWebEncryption = new JsonWebEncryption();
        jsonWebEncryption.setAlgorithmConstraints(new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.PERMIT, KeyManagementAlgorithmIdentifiers.DIRECT));
        jsonWebEncryption.setContentEncryptionAlgorithmConstraints(new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.PERMIT, ContentEncryptionAlgorithmIdentifiers.AES_128_CBC_HMAC_SHA_256));
        jsonWebEncryption.setCompactSerialization(idToken);
        jsonWebEncryption.setKey(jwk.getKey());
        return jsonWebEncryption.getPlaintextString();
    }
}

相关文档