技术标签: 苹果https java
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwk.Jwk;
import com.helijia.appuser.modules.user.vo.AppleCredential;
import com.helijia.common.api.model.ApiException;
import com.helijia.user.util.HttpClientUtil;
import com.helijia.user.util.UserCode;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.apache.commons.codec.binary.Base64;
import java.security.PublicKey;
import java.util.Map;
/**
* Created by laohu May 18 2020
*/
@Service
public class AppleService {
private static final Logger LOGGER = LoggerFactory.getLogger(AppleService.class);
private static final String AUTH_URL = "/auth/keys";
@Value("${apple.login.auth.url}")
public String appleUrl;
public void verify(AppleCredential credential) {
try {
String[] identityTokens = credential.getIdentityToken().split("\\.");
Map firstDate = JSONObject
.parseObject(new String(Base64.decodeBase64(identityTokens[0]), "UTF-8"));
Map secondData = JSONObject
.parseObject(new String(Base64.decodeBase64(identityTokens[1]), "UTF-8"));
String kid = String.valueOf(firstDate.get("kid"));
String aud = String.valueOf(secondData.get("aud"));
String sub = String.valueOf(secondData.get("sub"));
// 1.验证apple官方 2.sub和openId的一致性
if (verify(credential.getIdentityToken(), kid, aud, sub)) {
if(StringUtils.isEmpty(credential.getOpenId())) {
credential.setOpenId(sub);
}
return;
}
} catch (Exception e) {
LOGGER.error("apple identityToken verify error", e);
}
throw new ApiException(UserCode.USER_THIRD_ACCESSTOKEN_FAIL.getApiCode(),
UserCode.USER_THIRD_ACCESSTOKEN_FAIL.getApiMessage());
}
/**
* 验证
*
* @param identityToken APP获取的identityToken
* @param aud
* @param sub
* @return true/false
*/
private boolean verify(String identityToken, String kid, String aud, String sub) {
PublicKey publicKey = getPublicKey(kid);
JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey);
jwtParser.requireIssuer(appleUrl);
jwtParser.requireAudience(aud);
jwtParser.requireSubject(sub);
try {
Jws claim = jwtParser.parseClaimsJws(identityToken);
if (claim != null && claim.getBody().containsKey("auth_time")) {
return true;
}
return false;
} catch (ExpiredJwtException e) {
LOGGER.error("apple identityToken expired", e);
return false;
} catch (Exception e) {
LOGGER.error("apple identityToken illegal", e);
return false;
}
}
/**
* @param kid 通过kid获取对应的PublicKey
* {
* "keys": [
* {
* "kty": "RSA",
* "kid": "86D88Kf",
* "use": "sig",
* "alg": "RS256",
* "n": "iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ",
* "e": "AQAB"
* },
* {
* "kty": "RSA",
* "kid": "eXaunmL",
* "use": "sig",
* "alg": "RS256",
* "n": "4dGQ7bQK8LgILOdLsYzfZjkEAoQeVC_aqyc8GC6RX7dq_KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdDNq1n52TpxQwI2EqxSk7I9fKPKhRt4F8-2yETlYvye-2s6NeWJim0KBtOVrk0gWvEDgd6WOqJl_yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X-Tip84wqwyRpUlq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll-p_Dg8vAXxJLIJ4SNLcqgFeZe4OfHLgdzMvxXZJnPp_VgmkcpUdRotazKZumj6dBPcXI_XID4Z4Z3OM1KrZPJNdUhxw",
* "e": "AQAB"
* }
* ]
* }
* @return 构造好的公钥
*/
private PublicKey getPublicKey(String kid) {
try {
String str = HttpClientUtil.get(appleUrl + AUTH_URL);
JSONObject data = JSONObject.parseObject(str);
JSONArray jsonArray = data.getJSONArray("keys");
if(jsonArray.isEmpty()) {
return null;
}
for (Object object : jsonArray) {
JSONObject json = ((JSONObject)object);
if(json.getString("kid").equals(kid)) {
json = ((JSONObject)object);
Jwk jwa = Jwk.fromValues(json);
return jwa.getPublicKey();
}
}
} catch (final Exception e) {
LOGGER.error("apple getPublicKey error", e);
}
return null;
}
}
文章浏览阅读822次。vue中input输入框限制输入小数点后1位:<input @input="InputChange" v-model="clllci" /> InputChange(e) { console.log(e.target.value.match(/^\d*(\.?\d{0,2})/g)[0],6666) this.clllci = e.target.value.match(/^\d*(\.?\d{0,2})/g)[0] || null; },..._vue el-input 动态设置小数点后一位
文章浏览阅读364次。pdf.Cell(nil, "早上好,文艺范")使用循环让文本自动换行。//绘制带圆角的矩形。_gopdf 换行
文章浏览阅读920次,点赞12次,收藏14次。最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2019-2021面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。还有高级架构技术进阶脑图、Android开发面试专题资料帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
文章浏览阅读1.7k次。一、python3安装sudo apt install python3二、版本更换1查询已安装的python版本ls /usr/bin/python*显示在update-alternatives中有的python版本sudo update-alternatives --list python添加python版本到update-alternatives中,后面的数字越高优先级越高..._把/usr/bin/python和/usr/bin/python3链接到anaconda/bin
文章浏览阅读6.4k次,点赞2次,收藏38次。单目相机由于深度是未知的,因此我们需要对其进行初始化,在ORB-SLAM中将其用单独的类来表示,并将它写成单独的文件initializer.cc,注意单目相机即使在进行初始化之后,仍然存在尺度问题,初始化将第一帧的位移作为单位长度,后面的深度和位移都是依据这一标准进行的,所以尺度问题是单目slam的理论缺点。单目slam初始化需要两帧进行,第一帧作为参考初始化帧,第二帧作为当前帧。在第一帧来临时建..._orbslam的单目尺度
文章浏览阅读3.5k次。Java中文分词包——IK-Analyzer的maven项目依赖 <dependency> <groupId>com.janeluo</groupId> <artifactId>ikanalyzer</artifactId> <version>2012_u6</version&..._ikanalyzer依赖
文章浏览阅读4.2k次,点赞3次,收藏8次。详解excel数据查找分析定位中最常用的两个函数,vlookup以及sumifs_sumifs和vlookup合起来设公式
文章浏览阅读5.9k次。前言 配置深信服超融合时,用到的是第三方服务器,一般情况下网络构架搭建好和设备齐全后,经常会遇到问题是:HCI平台配置虚拟存储时如果第三方服务器有RAID,建议配置为直通(JBOD)模式,如果RAID卡不支持该模式,则要求将每个硬盘做成RAID 0逻辑盘,同时建议关闭RAID卡的写缓存,此时不支持硬盘热拔插!(但是不同的第三方服务器的jbod配置不一样!)H3C的R390X G2..._华三服务器开启硬盘直通
文章浏览阅读1.1k次,点赞6次,收藏9次。微软不建议再使用C的传统库函数scanf,strcpy,sprintf等,所以直接使用这些库函数会提示C4996错误。_vs2022 c4996
文章浏览阅读256次。本文是个人看视频总结,适合初学者标记含义说明性的标记 通常会放在文件的顶部包含普通的Java代码,_jspService方法外部包含普通的Java代码, _jspService方法内部包含普通的Java代码,通常是用来赋值和展示jsp文件中注释内容JSP编译:设计一个登录页面查询展示金额的例子部分代码:文件名称:showBal_jsp 用法
文章浏览阅读4k次,点赞6次,收藏34次。本文为Glide的基本使用技巧,基于Glide官方文档编写,适合未接触Glide的开发人员参考。_glide使用
文章浏览阅读908次。http://blog.csdn.net/rebel_321/article/details/4927464 用ifstream的eof(),竟然读到文件最后了,判断eof还为false。网上查找资料后,终于解决这个问题。参照文件:http://tuhao.blogbus.com/logs/21306687.html 在使用C/C++读文件的时候,一定都使用过eof()这个..._ifstream 读到了文件末尾以外的数据