苹果第三方登陆校验

@Value("${app.apple.login.key-id}")
private String keyId;
@Value("${app.apple.login.private-key}")
private String privateKey;
@Value("${app.apple.login.team-id}")
private String teamId;
@Value("${app.apple.login.client-id}")
private String clientId;

private static final String AuthUrl = "https://appleid.apple.com/auth/token";

@Autowired
private AccountManager accountManager;

@Override
public AccountThirdBO process(LoginRequest req) {
    if (StringUtils.isEmpty(req.getCode())){
        throw new BusinessException(ResultEnum.PARA_ERR);
    }
    String provider = AccountConstant.ProviderEnum.apple.toString();
    AuthRsp rsp = authCode(req.getCode(), keyId, privateKey, teamId, clientId);
    String thirdId = parseThirdId(rsp);

    AccountIndex accountIndex = accountManager.getAccountIndex(provider, thirdId);
    boolean unregistered = accountIndex == null;
    if (!unregistered) {
        accountManager.checkPhoneValidation(accountIndex.getUid());
    }

    List<ThirdInfo> thirdInfoList = new ArrayList<>();
    thirdInfoList.add(new ThirdInfo(provider, thirdId, thirdId, ""));

    return new AccountThirdBO(thirdInfoList,
            accountIndex == null ? null : accountIndex.getUid(),
            unregistered,
            false,
            unregistered);
}

private AuthRsp authCode(String code, String keyId, String privateKey, String teamId, String clientId){
    String clientSecret = ClientSecretGenerator.generate(keyId, privateKey, teamId, clientId);
    if (StringUtils.isEmpty(clientSecret)){
        throw new BusinessException(ResultEnum.ACCOUNT_LOGIN_AUTH_FAILED);
    }

    Map<String, String> header = new HashMap<>();
    header.put("Content-Type", "application/x-www-form-urlencoded");

    Map<String, String> req = new HashMap<>();
    req.put("client_id", clientId);
    req.put("client_secret", clientSecret);
    req.put("code", code);
    req.put("grant_type", "authorization_code");

    String rspBody =  HttpInvokeUtil.httpPost(AuthUrl, req, EncodeUtil.UTF8_ENCODE, header);
    if (StringUtils.isEmpty(rspBody) || rspBody.contains("error")){
        throw new BusinessException(ResultEnum.ACCOUNT_LOGIN_AUTH_FAILED);
    }
    AuthRsp rsp = JSONObject.parseObject(rspBody, AuthRsp.class);
    if (rsp == null || StringUtils.isEmpty(rsp.getIdToken())){
        throw new BusinessException(ResultEnum.ACCOUNT_LOGIN_AUTH_FAILED);
    }
    return rsp;
}

private String parseThirdId(AuthRsp rsp){
    String[] idTokens = rsp.getIdToken().split("\\.");
    if (idTokens.length < 2){
        throw new BusinessException(ResultEnum.ACCOUNT_LOGIN_AUTH_FAILED);
    }
    // 去掉签名
    String unsignedIdToken = idTokens[0] + "." + idTokens[1] + ".";
    Jwt<Header, Claims> jwt = Jwts.parserBuilder().build().parseClaimsJwt(unsignedIdToken);
    Claims claims = jwt.getBody();
    if (claims == null){
        throw new BusinessException(ResultEnum.ACCOUNT_LOGIN_AUTH_FAILED);
    }
    String thirdId =  (String)claims.get("sub");
    if (StringUtils.isEmpty(thirdId)){
        throw new BusinessException(ResultEnum.ACCOUNT_LOGIN_AUTH_FAILED);
    }
    return thirdId;
}

public static class ClientSecretGenerator{
    private ClientSecretGenerator(){}

    public static String generate(String keyId, String privateKey, String teamId, String clientId) {
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey.getBytes(Charsets.UTF_8)));
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("EC");
            PrivateKey key = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            return Jwts.builder()
                    .setHeader(genHeader(keyId))
                    .setClaims(genClaims(teamId, clientId))
                    .signWith(key, SignatureAlgorithm.ES256)
                    .compact();
        }catch (NoSuchAlgorithmException e){

        }catch (InvalidKeySpecException e){

        }
        return null;
    }

    private static Map<String, Object> genHeader(String keyId){
        Map<String, Object> headerMap = new HashMap<>();
        headerMap.put("alg", SignatureAlgorithm.ES256);
        headerMap.put("kid", keyId);
        return headerMap;
    }

    private static Map<String, Object> genClaims(String teamId, String clientId){
        Date now = new Date();
        Date atTime = TimeUtils.plusDays(now, -2);
        Date expireTime = TimeUtils.plusDays(now, 2);

        Map<String, Object> claimMap = new HashMap<>();
        claimMap.put("iss", teamId);
        claimMap.put("iat", atTime.getTime() / 1000);
        claimMap.put("exp", expireTime.getTime() / 1000);
        claimMap.put("aud", "https://appleid.apple.com");
        claimMap.put("sub", clientId);
        return claimMap;
    }
}

public static class AuthRsp{
    @JSONField(name = "access_token")
    private String accessToken;
    @JSONField(name = "expires_in")
    private Long expiresIn;
    @JSONField(name = "refresh_token")
    private String refreshToken;
    @JSONField(name = "id_token")
    private String idToken;

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public Long getExpiresIn() {
        return expiresIn;
    }

    public void setExpiresIn(Long expiresIn) {
        this.expiresIn = expiresIn;
    }

    public String getRefreshToken() {
        return refreshToken;
    }

    public void setRefreshToken(String refreshToken) {
        this.refreshToken = refreshToken;
    }

    public String getIdToken() {
        return idToken;
    }

    public void setIdToken(String idToken) {
        this.idToken = idToken;
    }
}

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值