苹果注销功能实现 Revoke tokens(JAVA)
Revoke tokens
前言
由于苹果新政策要求在2022年6月30日之后,使用Apple ID登录的账号注销时都要调用苹果的注销Api,趁这两天事情不是特别多就把注销功能给写了,顺便记录一下。
一:实现思路
官方文档: Revoke tokens
1.1. 苹果授权登录后,会返回authorizationCode这个授权码,利用授权码调用API来生成访问令牌(access_token)和刷新令牌(refresh_token)。
access_token:调用注销Api时所需的参数
refresh_token:调用刷新Token Api时所需的参数
access_token在这个时候用不上,因为是有有效期的,我们只需要在注销的时候重新获取access_token就可以了。这个时候要将refresh_token与这个用户进行绑定,可以将其存入数据库中,为了注销的时候可以用refresh_token来获取到新的access_token
1.2.使用refresh_token来更新新的access_token
1.3.用access_token调用 Revoke tokens Api
二:代码实现
maven
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version></dependency>
常量类
public class Const {//client_id(应用ID)public static final String CLIENT_ID = "";//teamId(苹果开发人员帐户关联的10 个字符的团队ID)public static final String TEAM_ID = "";//Key Id (P8证书下载后可以得到keyId,跟苹果开发人员拿)public static final String KEY_ID = "";//keyValue(P8文件下载后可以得到keyValue,跟苹果开发人员拿)public static final String KEY_VALUE = "";//AUD(固定的)public static final String REVOKE_AUD = "https://appleid.apple.com";//生成或刷新token的URLpublic static final String AUTH_TOKEN_URL = "https://appleid.apple.com/auth/token";//撤销用户token请求urlpublic static final String AUTH_REVOKE_URL = "https://appleid.apple.com/auth/revoke";
}
苹果授权登录成功后,根据authorizationCode授权码来获取refreshToken,将refreshToken与我们的用户绑定,可以存到数据库中
/*** 根据authorizationCode授权码来获取refreshToken*/public String generateToken(String authorizationCode) {String refreshToken = null;try {MultiValueMap<String, String> map = new LinkedMultiValueMap<>();map.add("client_id", Const.AUD);map.add("client_secret", generateClientSecret());map.add("grant_type", "authorization_code");map.add("code", authorizationCode);HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);String value = restTemplate.postForEntity(Const.AUTH_TOKEN_URL, request, String.class).getBody();if (StringUtils.isNotBlank(value)) {JSONObject json = JSONObject.fromObject(value);refreshToken = json.getString("refresh_token");}} catch (HttpClientErrorException e) {throw new WZHException(e.getResponseBodyAsString());//WZHException是我自定义的异常类} catch (Exception e) {throw new WZHException(e.getMessage());}return refreshToken;}
client_secret秘钥的生成
/*** 生成客户端密钥*/private static String generateClientSecret() throws Exception {Map<String, Object> header = new HashMap<>();header.put("kid", Const.KEY_ID); //P8文件下载得到的Key IDheader.put("alg", SignatureAlgorithm.ES256.getValue()); //SHA256Map<String, Object> claims = new HashMap<>();long now = new Date().getTime() / 1000;claims.put("iss", Const.TEAM_ID);claims.put("iat", now);claims.put("exp", now + 648000); // 最长半年,单位秒claims.put("aud", Const.REVOKE_AUD);claims.put("sub", Const.CLIENT_ID);PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(Const.KEY_VALUE));//P8文件下载得到的Key ValueKeyFactory keyFactory = KeyFactory.getInstance("EC");PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);return Jwts.builder().setHeader(header).setClaims(claims).signWith(SignatureAlgorithm.ES256, privateKey).compact();}
Revoke tokens的第一种方式:使用refreshToken进行注销
public Response<String> revokeToken() {LoginUser loginUser = getFrontUser();//从缓存获取当前登录的信息try {User user = userService.getById(loginUser.getId());//获取用户的refreshTokenMultiValueMap<String, String> map = new LinkedMultiValueMap<>();map.add("client_id", Const.CLIENT_ID);map.add("client_secret", generateClientSecret());map.add("token_type_hint", "refresh_token");map.add("token", user.getRefreshToken());HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);ResponseEntity<String> values = restTemplate.postForEntity(Const.AUTH_REVOKE_URL, request, String.class);log.info("注销token成功");//Apple官网上请求只有200与400,这里没有抛异常,证明是成功注销的return Response.success("Revoke tokens success.");} catch (HttpClientErrorException e) {throw new WZHException(e.getResponseBodyAsString());} catch (Exception e) {throw new WZHException(e.getMessage());}}
Revoke tokens的第二种方式:使用refreshToken来刷新accessToken,再用accessToken来进行注销(个人推荐)
/*** 根据refreshToken刷新accessToken*/private String refreshToken(String refreshToken) {String accessToken = null;try {MultiValueMap<String, String> map = new LinkedMultiValueMap<>();map.add("client_id", Const.CLIENT_ID);map.add("client_secret", generateClientSecret());map.add("grant_type", "refresh_token");map.add("refresh_token", refreshToken);HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);String value = restTemplate.postForEntity(Const.AUTH_TOKEN_URL, request, String.class).getBody();if (StringUtils.isNotBlank(value)) {JSONObject json = JSONObject.fromObject(value);accessToken = json.getString("access_token");}} catch (HttpClientErrorException e) {throw new WZHException(e.getResponseBodyAsString(), 401);} catch (Exception e) {throw new WZHException(e.getMessage(), 401);}log.info("刷新token成功");return accessToken;}
/*** 撤销用户token*/public Response<String> revokeToken() {LoginUser loginUser = getFrontUser();//从缓存获取当前登录的信息try {User user = userService.getById(loginUser.getId());String accessToken = refreshToken(user.getRefreshToken());//更新accessTokenMultiValueMap<String, String> map = new LinkedMultiValueMap<>();map.add("client_id", Const.CLIENT_ID);map.add("client_secret", generateClientSecret());map.add("token_type_hint", "access_token");map.add("token", accessToken);HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);ResponseEntity<String> values = restTemplate.postForEntity(Const.AUTH_REVOKE_URL, request, String.class);log.info("注销token成功");//Apple官网上请求只有200与400,这里没有抛异常,证明是成功注销的return Response.success("Revoke tokens success.");} catch (HttpClientErrorException e) {throw new WZHException(e.getResponseBodyAsString());} catch (Exception e) {throw new WZHException(e.getMessage());}}
注意事项
Revoke tokens成功之后,数据库上用户绑定的refreshToken就无效了,如果再次用refreshToken去更新accessToken时,会抛
{\"error\":\"invalid_grant\",\"error_description\":\"The token has expired or has been revoked.\"}
异常,所以要根据公司具体的业务来,如果注销后可以重新登录的话,就在注销成功的时候将用户绑定的refreshToken清除掉,然后下次登录的时候重新利用authorizationCode来生成refreshTokenrevokeToken时,只要不抛异常,就证明是成功的操作,如果accessToken是错的,苹果的Api也会返回成功,因为苹果会认为这是被注销过的,所以我们的只要确保accessToken的值是没问题的就可以了
Apple账户修改了密码之后,refreshToken的值也会失效,所以在注销的时候,如果发现refreshToken已经失效了,得将用户绑定的refreshToken进行清除掉,同时得有个动作让用户进行重新授权来更新refreshToken。
苹果注销功能实现 Revoke tokens(JAVA)相关推荐
- Sign in with Apple REST API / Revoke tokens (JAVA)
Sign in with Apple REST API / Revoke tokens (JAVA) 前言 由于Apple政策, Apple ID登录的用户注销时需要进行Revoke Token. 顺 ...
- Spring Cloud 架构设计之苹果Apple账户注销 Revoke tokens auth/revoke
Spring Cloud 架构设计之苹果Apple账户注销 Revoke tokens auth/revoke 前言 近期,本人在开发一款互联网产品,项目地址https://github.com/yj ...
- java实现注销功能_8.6.2 登录注销功能的实现
8.6.2 登录注销功能的实现 9.6.1节介绍了登录页面的搭建,本节将介绍如何实现登录的业务功能,包括Servlet端的业务逻辑和数据库端的用户名和密码验证等. 在开发一个Servlet之前,需要 ...
- 「小程序JAVA实战」小程序我的个人信息-注销功能(42)
转自:https://idig8.com/2018/09/06/xiaochengxujavashizhanxiaochengxuwodegerenxinxi-zhuxiaogongneng40/ 注 ...
- java注销对话框_【java小程序实战】小程序注销功能实现
小程序实战中,如何实现程序的注销功能呢?后端代码只要删除用户的redi缓存即可.小程序端在成功返回消息后,进行登陆页面的跳转. 文章目录 小程序的mine.wxml代码 mine.wxss代码 注销事 ...
- 【java小程序实战】小程序注销功能实现
小程序实战中,如何实现程序的注销功能呢?后端代码只要删除用户的redi缓存即可.小程序端在成功返回消息后,进行登陆页面的跳转. 文章目录 小程序的mine.wxml代码 mine.wxss代码 注销事 ...
- 这可能是史上功能最全的Java权限认证框架!
点击关注公众号,Java干货及时送达 今天给大家推荐的这个开源项目超级棒,可能是史上功能最全的 Java 权限认证框架! 这个开源项目就是:sa-token . Sa-Token是什么? sa-tok ...
- iOS13苹果登录的后台验证token(JAVA)
最近随着iOS的更新,苹果要求含有第三方登录的app必须实现苹果登录功能,在查询相关资料后整合进自己的项目中,再次记录下,也供大家借鉴. 以下是大致流程,挺简单的: 首先引入解析jwt的包: < ...
- 绿豆APP源码苹果CMS影视插件版本原生JAVA源码
纯净原版绿豆APP源码苹果CMS影视插件版本原生JAVA源码,这套绿豆源码相当完美运行非常流畅,纯原汁原味的绿豆UI,不是市面上被改的乱七八糟的版本,其实大家也清楚网上卖几百的也只是换个底图换个图标而 ...
最新文章
- 万字详解,JDK1.8新特性的Lambda、Stream和日期的使用详解
- 在JavaScript函数中定义全局变量
- 无聊写的一个PHP Socket类
- [POJ3254]Corn Fields
- 在数据库中如果组合主键(假设为stuID和stuName)存在则更新,不存在则新增
- vs2010无法添加dll引用
- ubuntu虚拟显示器远程连接桌面方案
- 下载网页视频 下载网页音乐 一般视频音频和m3u8均可
- android 放大镜功能,利用Android实现一个放大镜功能
- 电子凸轮应用追剪算法详细图解(附PLC完整源代码)
- 2023年全国最新工会考试精选真题及答案36
- php cli python,PHP MVC框架 CodeIgniter CLI模式简介
- 双十一要不要提前收货
- 惠普linux进入bios设置u盘启动,如何进入bios设置,手把手教你惠普如何进入bios设置u盘启动...
- 【报告分享】中国消费者洞察报告-领航前所未有(附下载)
- 一定要注意网站图片版权问题!
- 华师大 OJ 3055
- 你还在为无法完美卸载SQL Server 2008 R2而烦恼吗?
- 【简书 DC谢老师】JMeter + jenkins + SVN 接口自动化之简单 demo​​​​​​​
- 重庆师范计算机录取分数线,重庆师范大学历年录取分数线