将AuthenticationHelper示例类从 v1 sdk 转换为 v2 并不太困难。v1 调用只需更新到 v2 版本。所有 SRP 生成保持不变。下面是我如何将该类的主要方法转换为使用 v2 sdk。
执行 SRP 身份验证
public String PerformSRPAuthentication(String username, String password) {
String authresult = null;
InitiateAuthRequest authReq = initiateUserSrpAuthRequest(username);
try {
AnonymousCredentialsProvider creds = AnonymousCredentialsProvider.create();
CognitoIdentityProviderClient cognitoclient = CognitoIdentityProviderClient.builder()
.region(Region.of(this.region))
.credentialsProvider(creds)
.build();
InitiateAuthResponse authRes = cognitoclient.initiateAuth(authReq);
if(authRes.challengeName().equals(ChallengeNameType.PASSWORD_VERIFIER)) {
RespondToAuthChallengeRequest challengeRequest = userSrpAuthRequest(authRes, password);
RespondToAuthChallengeResponse result = cognitoclient.respondToAuthChallenge(challengeRequest);
authresult = result.authenticationResult().idToken();
}
} catch(Exception e) {
System.out.println("Exception: " + e);
}
return authresult;
}
发起UserSrpAuthRequest
private InitiateAuthRequest initiateUserSrpAuthRequest(String username) {
HashMap<String, String> authParams = new HashMap<String, String>();
authParams.put("USERNAME", username);
authParams.put("SRP_A", this.getA().toString(16));
InitiateAuthRequest authReq = InitiateAuthRequest.builder()
.authFlow(AuthFlowType.USER_SRP_AUTH)
.clientId(this.clientId).authParameters(authParams).build();
return authReq;
}
userSrpAuthRequest
private RespondToAuthChallengeRequest userSrpAuthRequest(InitiateAuthResponse challenge,
String password
) {
String userIdForSRP = challenge.challengeParameters().get("USER_ID_FOR_SRP");
String usernameInternal = challenge.challengeParameters().get("USERNAME");
BigInteger B = new BigInteger(challenge.challengeParameters().get("SRP_B"), 16);
if (B.mod(AWSAuthenticationHelper.N).equals(BigInteger.ZERO)) {
throw new SecurityException("SRP error, B cannot be zero");
}
BigInteger salt = new BigInteger(challenge.challengeParameters().get("SALT"), 16);
byte[] key = getPasswordAuthenticationKey(userIdForSRP, password, B, salt);
Date timestamp = new Date();
byte[] hmac = null;
try {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA256");
mac.init(keySpec);
mac.update(this.userPoolID.split("_", 2)[1].getBytes(Charset.forName("UTF-8")));
mac.update(userIdForSRP.getBytes(Charset.forName("UTF-8")));
byte[] secretBlock = Base64.decode(challenge.challengeParameters().get("SECRET_BLOCK"));
mac.update(secretBlock);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy", Locale.US);
simpleDateFormat.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
String dateString = simpleDateFormat.format(timestamp);
byte[] dateBytes = dateString.getBytes(Charset.forName("UTF-8"));
hmac = mac.doFinal(dateBytes);
} catch (Exception e) {
System.out.println(e);
}
SimpleDateFormat formatTimestamp = new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy", Locale.US);
formatTimestamp.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
Map<String, String> srpAuthResponses = new HashMap<>();
srpAuthResponses.put("PASSWORD_CLAIM_SECRET_BLOCK", challenge.challengeParameters().get("SECRET_BLOCK"));
srpAuthResponses.put("PASSWORD_CLAIM_SIGNATURE", new String(Base64.encode(hmac), Charset.forName("UTF-8")));
srpAuthResponses.put("TIMESTAMP", formatTimestamp.format(timestamp));
srpAuthResponses.put("USERNAME", usernameInternal);
RespondToAuthChallengeRequest authChallengeRequest = RespondToAuthChallengeRequest.builder()
.challengeName(challenge.challengeName())
.clientId(clientId)
.session(challenge.session())
.challengeResponses(srpAuthResponses).build();
return authChallengeRequest;
}
您还需要替换两个 v1 实用程序类com.amazonaws.util.Base64
和com.amazonaws.util.StringUtils
. 的所有实例StringUtils.UTF8
都可以替换为java.nio.charset.Charset.forName("UTF-8")
。更换Base64
有点棘手。我最终只是将 4 个相关类复制到本地项目中。那些正在
com.amazonaws.util.Base64
com.amazonaws.util.CodecUtils
com.amazonaws.util.Codec
com.amazonaws.util.Base64Codec
它不漂亮,但它对我有用。我不确定为什么 AWS 不能像所有其他 SDK 一样为 SRP 身份验证实现包装器。