問題描述
我已經實現了新的蘋果功能使用 Apple 登錄"的應用程序端,但我無法在我的后端使用授權碼進行驗證.我的后端是用 java 編寫的,我無法生成 JWT 并與 Apple 服務器通信.
I've implemented the app side of the new apple feature "Sign in with Apple" but i'm unable to verificate with authorizationCode in my backend. My backend is written in java and i'm unable to generate JWT and communicate with Apple servers.
推薦答案
先去 developer.apple.com ->證書、標識符和配置文件 ->鑰匙.為 Apple 登錄生成密鑰并下載此密鑰.您無法再次下載此密鑰,因此請將其保存在安全的地方,不要與他人共享.此外,您在此處顯示的密鑰 ID 請注意這一點,稍后您將需要它.您還需要團隊 ID.如果你不知道,它會寫在頁面的右上角,比如 YOURNAME - XX0XX00XXX.
First go developer.apple.com -> Certificates, Identifiers & Profiles -> Keys. Generate a key for Apple Sign in and download this key. You can not download this key again so keep it in a safe place and don't share with others. Also your Key ID shown here note this, you'll need this later. You'll also need team id. If you don't know it, it's written top right of the page like YOURNAME - XX0XX00XXX.
您將基本上遵循這些步驟.
You will basicly follow these steps.
1.從您的密鑰生成 JWT
1.Generate JWT from your key
2.使用您的令牌發送驗證碼
2.Send auth code with your token
3.解碼響應
同時使用網絡和移動設備的更新
如果您想在網頁上使用 Apple 登錄,則需要執行更多步驟.
If you would like to use apple login for web there are few more steps you need to follow.
4.添加新的網絡標識符
去 developer.apple.com ->證書、標識符和配置文件 ->身份標識.單擊加號按鈕注冊新標識符.選擇服務 ID 并繼續.提供描述和標識符.標識符必須是唯一的,并且與您的捆綁包 ID 不同.(例如,您可以使用 com.your.bundle.id.web).點擊繼續點擊注冊.然后你需要配置這個服務ID.選擇服務 ID(它位于搜索圖標附近的右上角)您在下面列出的新創建的服務 ID 單擊它并
啟用使用 Apple 登錄復選框.然后你需要配置你的域.提供您的域名并返回網址.
go developer.apple.com -> Certificates, Identifiers & Profiles -> Identifiers. Register a new identifier with clicking plus button. Select Service IDs and continue. Provide a description and identifier. Identifier must be unique and different from your bundle id. (for example you can use com.your.bundle.id.web). Click continue click register. Then you need to configure this service id. Select Service IDs (It's placed at top right near search icon) your newly created services id listed below click it and
enable Sign In with Apple tick box. Then you need to configure your domain. provide your domain and return url.
如果您忘記傳遞 valid redirect_url 或嘗試多次使用相同的authorization_code.
Some important points for web you can get invalid_grant error if you forgot to pass a valid redirect_url or try to use same authorization_code more than once.
public class AppleLoginUtil {
private static String APPLE_AUTH_URL = "https://appleid.apple.com/auth/token";
private static String KEY_ID = "**********";
private static String TEAM_ID = "**********";
private static String CLIENT_ID = "com.your.bundle.id";
private static String WEB_CLIENT_ID = "com.your.bundle.id.web";
private static String WEB_REDIRECT_URL = "https://bundle.your.com/";
private static PrivateKey pKey;
private static PrivateKey getPrivateKey() throws Exception {
//read your key
String path = new ClassPathResource("apple/AuthKey.p8").getFile().getAbsolutePath();
final PEMParser pemParser = new PEMParser(new FileReader(path));
final JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
final PrivateKeyInfo object = (PrivateKeyInfo) pemParser.readObject();
final PrivateKey pKey = converter.getPrivateKey(object);
return pKey;
}
private static String generateJWT() throws Exception {
if (pKey == null) {
pKey = getPrivateKey();
}
String token = Jwts.builder()
.setHeaderParam(JwsHeader.KEY_ID, KEY_ID)
.setIssuer(TEAM_ID)
.setAudience("https://appleid.apple.com")
.setSubject(CLIENT_ID)
.setExpiration(new Date(System.currentTimeMillis() + (1000 * 60 * 5)))
.setIssuedAt(new Date(System.currentTimeMillis()))
.signWith(pKey, SignatureAlgorithm.ES256)
.compact();
return token;
}
private static String generateWebJWT() throws Exception {
String token = Jwts.builder()
.setHeaderParam(JwsHeader.KEY_ID, KEY_ID)
.setIssuer(TEAM_ID)
.setAudience("https://appleid.apple.com")
.setSubject(WEB_CLIENT_ID)
.setExpiration(new Date(System.currentTimeMillis() + (1000 * 60 * 5)))
.setIssuedAt(new Date(System.currentTimeMillis()))
.signWith(getPrivateKey(), SignatureAlgorithm.ES256)
.compact();
return token;
}
/*
* Returns unique user id from apple
* */
public static String appleAuth(String authorizationCode, boolean forWeb) throws Exception {
HttpResponse<String> response = Unirest.post(APPLE_AUTH_URL)
.header("Content-Type", "application/x-www-form-urlencoded")
.field("client_id", forWeb ? WEB_CLIENT_ID : CLIENT_ID)
.field("client_secret", forWeb ? generateWebJWT() : generateJWT())
.field("grant_type", "authorization_code")
.field("code", authorizationCode)
.field("redirect_uri", forWeb ? WEB_REDIRECT_URL : null)
.asString();
TokenResponse tokenResponse=new Gson().fromJson(response.getBody(),TokenResponse.class);
String idToken = tokenResponse.getId_token();
String payload = idToken.split("\.")[1];//0 is header we ignore it for now
String decoded = new String(Decoders.BASE64.decode(payload));
IdTokenPayload idTokenPayload = new Gson().fromJson(decoded,IdTokenPayload.class);
return idTokenPayload.getSub();
}
}
我使用 BouncyCastle jjwt 來生成令牌.還有用于休息呼叫的 unirest 和 gson.
I've used BouncyCastle jjwt for generating token. And also unirest and gson for rest calls.
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.63</version>
</dependency>
<!--JJWT-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.10.7</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.10.7</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.7</version>
<scope>runtime</scope>
</dependency>
<!--UNIREST-->
<dependency>
<groupId>com.mashape.unirest</groupId>
<artifactId>unirest-java</artifactId>
<version>1.4.9</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.3.6</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20140107</version>
</dependency>
如果你想知道的話,我還解析了對這些類的響應.
I've also parsed the responses to these classes if you wanted to know.
public class TokenResponse {
private String access_token;
private String token_type;
private Long expires_in;
private String refresh_token;
private String id_token;
..getters and setters
}
public class IdTokenPayload {
private String iss;
private String aud;
private Long exp;
private Long iat;
private String sub;//users unique id
private String at_hash;
private Long auth_time;
private Boolean nonce_supported;
private Boolean email_verified;
private String email;
..getters and setters
}
這篇關于使用 Apple Java 用戶驗證登錄的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!