1. 環境
SpringBoot に基づいてサードパーティ呼び出しを提供するインターフェイスを作成します。Alibaba の音声認識機能を使用する方法と同様に、HTTP リクエストを送信して音声認識を行う Alibaba のパッケージ化された API を呼び出すことができます。この記事では主に、SpringBoot でインターフェイスを開発し、他のユーザーがそれらを安全に呼び出せるようにする方法を記録します。
使用される依存関係:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>top.lukeewin</groupId>
<artifactId>Signature</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Signature</name>
<description>Signature</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 暗号化アルゴリズムの選択
MD5 アルゴリズムを使用した暗号化はあまり安全ではないため、ここではHmacSHA256
ハッシュ アルゴリズムの暗号化アルゴリズムを使用して署名を生成します。インターフェイスをリクエストするときは、署名とタイムスタンプを使用します。なぜタイムスタンプを持ってくる必要があるのでしょうか?後で署名の有効期限を制御したい場合は、フロントエンドによって渡されたタイムスタンプに基づいて有効期限を計算する必要があるためです。
暗号化ツールのクラスは次のとおりです。
public class SignatureUtil {
public static String getSignature(String timestamp, String apiKey, String apiSecret) {
// 构建签名字符串
String signatureString = apiKey + timestamp;
String signature = null;
// 计算签名
try {
Mac sha256Hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256Hmac.init(secretKey);
byte[] signatureBytes = sha256Hmac.doFinal(signatureString.getBytes(StandardCharsets.UTF_8));
signature = Base64.getEncoder().encodeToString(signatureBytes);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException(e);
}
return signature;
}
}
3. インターフェースを書く
ここでは、オーディオ トランスコーディング インターフェイスを作成して、インターフェイスの開発プロセス全体をシミュレートします。
@RestController
public class TransferController {
@RequestMapping("/transfer")
public BaseResponse transfer() {
return BaseResponse.success("转码成功");
}
@RequestMapping("/ban")
public BaseResponse ban() {
return BaseResponse.error(ErrorCode.VERIFY_NO_PASS);
}
}
4. インターセプターをカスタマイズする
インターセプタをカスタマイズして、包括的なリクエストをインターセプトし、署名とタイムスタンプが渡されたかどうかを判断します。また、渡された署名がバックエンドによって計算された署名と矛盾しているかどうかも判断します。また、署名が渡されたときに署名の有効期限が切れているかどうかも判断する必要があります。上記の条件のいずれかが満たされない場合はインターセプトされ、満たされない場合は解放されます。
@Component
public class SignatureInterceptor implements HandlerInterceptor {
@Value("${apiKey}")
private String apiKey;
@Value("${apiSecret}")
private String apiSecret;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String sign = request.getParameter("sign");
String timestamp = request.getParameter("timestamp");
if (StringUtils.isNotBlank(sign) && StringUtils.isNotBlank(timestamp)) {
String signature = SignatureUtil.getSignature(timestamp, apiKey, apiSecret);
if (StringUtils.isNotBlank(signature) && signature.equals(sign) && System.currentTimeMillis() - Long.parseLong(timestamp) < 50 * 1000) {
return true;
} else {
request.getRequestDispatcher("/ban").forward(request, response);
return false;
}
} else {
request.getRequestDispatcher("/ban").forward(request, response);
return false;
}
}
}
注意点:
- このクラスは、管理のために Spring IOC コンテナに引き渡す必要があります。つまり、クラスにアノテーションを追加する必要があります。
@Component
- インターセプト後、呼び出し元にプロンプトを表示する必要があります。そうしないと、呼び出し元はプロンプトがインターセプトされたかどうかわからないため、ここで使用する必要があります。
request.getRequestDispatcher("/ban").forward(request, response);
- インターセプトは解放する必要があります
URL
。解放しないと無限ループが発生します。ここで/ban
インターフェースを解放する必要があります。
5. インターセプター構成クラスを作成します。
インターセプター構成クラスを作成し、カスタム インターセプターを構成クラスに追加します。
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Resource
private SignatureInterceptor signatureInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(signatureInterceptor).addPathPatterns("/**").excludePathPatterns("/ban");
}
}
注意点:
@Configuration
注釈は必須です- 新しいカスタム インターセプター クラスを使用して追加することはできません。インジェクションを使用して挿入する必要があります。つまり、このように書くことはできません
registry.addInterceptor(new SignatureInterceptor()).addPathPatterns("/**")
6. インターフェースの応答フォーマットを統一する
2 つのツール クラスを作成します。1 つは応答基本クラスで、もう 1 つはエラー クラスです。
応答基本クラス:BaseResponse
@Data
public class BaseResponse<T> implements Serializable {
private static final long serialVersionUID = 4L;
private Integer code;
private String message;
private Long timestamp = System.currentTimeMillis();
private T data;
public static <T> BaseResponse<T> success(T data) {
BaseResponse<T> resultData = new BaseResponse<>();
resultData.setCode(200);
resultData.setMessage("OK");
resultData.setData(data);
return resultData;
}
public static BaseResponse error(ErrorCode errorCode) {
BaseResponse resultData = new BaseResponse();
resultData.setCode(errorCode.getCode());
resultData.setMessage(errorCode.getMessage());
return resultData;
}
}
@Data
ここでは提供されているアノテーションが使用されているため、アノテーションに依存関係を導入するlombok
必要があります。pom.xml
lombok
書き込みエラーコードクラス:ErrorCode
public enum ErrorCode {
VERIFY_NO_PASS(300, "签名验证未通过");
private final Integer code;
private final String message;
ErrorCode(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
7. 設定ファイル
カスタム インターセプターでは、@Value
アノテーションを通じてプロジェクトの構成ファイルから合計をapplication.yml
取得します。apiKey
apiSecret
application.yml
ファイルは次のとおりです。
apiKey: dhkadj123fda
apiSecret: hgjdakf12314sdf
対応するビデオチュートリアルがステーション B にアップロードされています。テキストコンテンツを読みたくない場合は、ビデオを見ることもできます。