如何在SpringBoot应用中通过Rest Template直接获取DocuSign JWT Access Token?
解决方案:SpringBoot中直接通过Rest API生成DocuSign JWT Access Token
当然可以直接在应用内通过Rest API调用生成JWT Access Token,你之前走的是授权码流程(需要手动获取code),而JWT认证本身就是为服务端应用设计的无交互授权方式,只需要完成一次初始用户授权后,就能全程在应用内自动获取Token。
必要前提
在开始前,你需要准备好这些信息:
- 集成密钥(API Key):从DocuSign开发者控制台获取
- RSA私钥:在DocuSign控制台生成并下载的
.pem文件 - 拟 impersonate 的用户ID:目标用户的DocuSign ID(可从用户详情页获取)
- DocuSign环境地址:开发环境用
account-d.docusign.com,生产环境用account.docusign.com - 已完成首次用户授权:用浏览器访问
https://{server}/oauth/auth?response_type=code&scope=signature%20impersonation&client_id={集成密钥}&redirect_uri={你的回调地址},完成授权后这个步骤后续无需重复执行
实现步骤
1. 添加依赖
在build.gradle中添加JWT处理和HTTP请求的依赖:
dependencies { // JJWT库用于生成JWT断言 implementation 'io.jsonwebtoken:jjwt-api:0.11.5' runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5' // Spring Web用于RestTemplate implementation 'org.springframework.boot:spring-boot-starter-web' }
2. 生成JWT断言
编写工具方法加载私钥并生成符合DocuSign要求的JWT:
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.Base64; import java.util.Date; public class DocusignJwtUtils { // 加载RSA私钥 public static PrivateKey loadPrivateKey(String privateKeyPath) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { String key = new String(Files.readAllBytes(Paths.get(privateKeyPath))) .replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", "") .replaceAll("\\s", ""); byte[] keyBytes = Base64.getDecoder().decode(key); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory kf = KeyFactory.getInstance("RSA"); return kf.generatePrivate(spec); } // 生成JWT断言 public static String generateJwtAssertion(String apiKey, String userId, String serverUrl, PrivateKey privateKey) { long expirationMillis = System.currentTimeMillis() + 3600000; // 1小时过期,DocuSign允许的最长时间 return Jwts.builder() .setIssuer(apiKey) .setSubject(userId) .setAudience(serverUrl) .setExpiration(new Date(expirationMillis)) .claim("scope", "signature impersonation") .signWith(privateKey, SignatureAlgorithm.RS256) .compact(); } }
3. 用RestTemplate调用Token接口获取Access Token
编写服务类调用DocuSign的OAuth token接口:
import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; import java.security.PrivateKey; import java.util.Map; @Service public class DocusignAuthService { private final RestTemplate restTemplate; public DocusignAuthService(RestTemplate restTemplate) { this.restTemplate = restTemplate; } public String getJwtAccessToken(String apiKey, String userId, String serverUrl, PrivateKey privateKey) { String jwtAssertion = DocusignJwtUtils.generateJwtAssertion(apiKey, userId, serverUrl, privateKey); // 构建请求参数 MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); params.add("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"); params.add("assertion", jwtAssertion); // 设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers); String tokenUrl = "https://" + serverUrl + "/oauth/token"; // 调用接口并解析返回结果 ResponseEntity<Map> response = restTemplate.postForEntity(tokenUrl, request, Map.class); return (String) response.getBody().get("access_token"); } }
4. 配置RestTemplate
在SpringBoot配置类中注册RestTemplate:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class AppConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
注意事项
- 确保私钥文件路径正确,且应用有读取权限
- JWT的过期时间不能超过1小时,否则会被DocuSign拒绝
- 首次授权必须完成,否则JWT请求会返回
consent_required错误,此时需要引导用户完成授权流程
内容的提问来源于stack exchange,提问作者Sunit Kale
相关产品推荐
相关产品推荐

