企业API使用
场景简介
OneAccess提供第三方API的授权管理功能,API提供者将API配置到OneAccess之后,API消费者在使用API之前需要先到OneAccess获取鉴权Token,在使用API时携带该鉴权Token,API提供者根据鉴权Token判断是否可以提供服务,用以实现API的授权管理功能。
前提条件
请确保您已拥有OneAccess管理门户的访问权限。
在OneAccess中添加企业应用
在OneAccess管理门户中添加企业应用,提供给API使用者获取鉴权Token信息。
- 登录OneAccess管理门户。
- 在导航栏中,单击“资源 > 应用”。
- 在企业应用页面,单击自建应用下的“添加自建应用”,设置Logo和名称,单击“保存”。
- 获取的ClientId和ClientSecret。
在应用信息页面单击应用图标,在应用详情页面获取ClientId和ClientSecret(此信息需要提供给API使用者)。
- ClientSecret需单击“启用”生成。
- ClientSecret是校验开发者身份的密码,具备高安全性,切勿将其直接提供给第三方开发者或直接存储在代码中。
- 重置后的ClientSecret即时生效,所有使用原ClientSecret的接口将全部失效,请谨慎重置。
- OneAccess不存储ClientSecret,当获取ClientSecret后,请妥善保管。
在OneAccess中添加企业API
OneAccess管理员在OneAccess管理门户中添加企业需要的自定义API产品。
- 登录OneAccess管理门户。
- 在导航栏中,单击“资源 > 企业API”。
- 在企业API页面,单击自定义API产品下的“添加自定义API产品”。
- 在“添加企业API”页面,上传产品LOGO,填写产品名称和描述,单击“确定”,自定义API产品添加完成,自定义API产品页面显示已添加的API产品。
- 单击新建的自定义API产品,切换到“应用授权”页签,单击在OneAccess中添加企业应用中新建的应用后的“授权”,完成API对应用的授权使用。
- 切换到“权限信息”页面,添加API权限信息。
在OneAccess应用中授权相应API权限
在OneAccess的应用中,授权具体自定义API的权限。
- 登录OneAccess管理门户。
- 在导航栏中,单击“资源 > 应用”。
- 单击在OneAccess中添加企业应用中新建的应用,单击应用图标,进入通用信息页面。
- 选择“API权限 ”,在API权限页面,单击某一权限代码右侧“操作”列的“授权”则授权成功。
在OneAccess中获取签名公钥和算法密钥
OneAccess颁发的鉴权Token是经过加密和签发的,需要获取签名公钥和算法密钥给API提供者进行解密。
- 登录OneAccess管理门户。
- 在导航栏中,选择“设置 > 服务配置”,单击“API认证配置”,获取签名公钥和算法密钥,提供给API提供者。
OneAccess不展示算法密钥,当重置算法密钥后,请妥善保管。
API使用者从OneAccess获取鉴权Token
API使用者调用OneAccess鉴权接口获取鉴权Token。
访问接口:https://访问域名/api/v2/tenant/token?grant_type=client_credentials。
PostMan调用示例:
- 访问域名为用户访问域名。可在OneAccess实例详情页获取。。
- 使用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(); } }