记springboot配置ios通用链接

目录

一、什么是IOS通用链接:

二、Springboot配置apple-app-site-association文件

一、什么是IOS通用链接:
在app开发中我们经常需要从浏览器,Safari中去唤醒app,iOS 9之前我们通过配置scheme从而实现这种跳转,但是这种方式需要提前判断系统中是否安装了能够响应对应scheme的app,这种方式在微信中是被禁用的。Universal Links是iOS 9推出的一项功能,我们可以通过配置Universal Links使用户能够通过一个链接进入app或者指定页面,这个不会被微信禁用。

IOS官方文档地址:https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html#//apple_ref/doc/uid/TP40016308-CH12-SW1

IOS端参考配置地址:https://www.jianshu.com/p/0c2af36aa6ac

二、Springboot配置apple-app-site-association文件
根据官方文档要求,仅需要在根目录下配置该文件,就可以交由ios跳转的进行校验。

项目环境:

1. springboot 2.2.3.RELEASE

2. 该项目是jar包运行,估没有webapp,但有static文件夹

%title插图%num

%title插图%num

 

配置完毕,直接访问:localhost/apple-app-site-association,即完成配置

demo地址:https://gitee.com/banbeisudashui/ios_apple_demo

SpringBoot Java后端校验Sign in With Apple (苹果授权登录)

先吐槽一下!苹果的开发文档简直就是一坨S

好了!!开发步骤如下:
1.导入JWT Maven 坐标

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>

2.闭上眼睛,以GET方式不带参数访问 https://appleid.apple.com/auth/keys。获取*新JSON,对我们有用的就是”n”和”e”,组成JWT公钥(此处官方有变更,现在获取到的keys数组为多个,需要根据下面第三步IOS端获取的identityToken中的kid来找对应下标的keys数组)。

获取到的json内容:
{
“keys”: [
{
“kty”: “RSA”,
“kid”: “AIDOPK1”,
“use”: “sig”,
“alg”: “RS256”,
“n”: “(可能每次都不一样)xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”,
“e”: “AQAB”
}
]
}

ps.我这里使用的是SpringBoot RestTemplate的GET请求方式,然后根据上面的”n”和”e”组成公钥:

AUTH_DOMAIN = https://appleid.apple.com/auth/keys
AppleKeys:请求返回数据的对象
RSA = RSA
public PublicKey getPublicKey() {
try {
String forObject = restTemplate.getForObject(AUTH_DOMAIN, String.class);
if(StringUtils.isEmpty(forObject)){ return null; }
AppleKeys appleKeys = JsonUtils.parseObject(forObject, AppleKeys.class);
List<AppleKeys.Keys> keys = appleKeys.getKeys();
String n = keys.get(0).getN();
String e = keys.get(0).getE();
final BigInteger modulus = new BigInteger(1, Base64.decodeBase64(n));
final BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(e));
final RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, publicExponent);
final KeyFactory kf = KeyFactory.getInstance(RSA);
return kf.generatePublic(spec);
} catch (final Exception e) {
log.debug(“[APPLE]ERROR:{}”,e)
}
return null;
}

3.IOS客户端经过一系列操作获取到:identityToken,userID等。将identityToken传递到后台(其他参数没啥用)

4.后台取到IOS客户端传过来的 identityToken 是jwt格式(固定三段式以“.”切割…我们只需要取第二段即可)。然后使用Base64解析出来,里面对我们有用的数据只有三个字段:

“iss”=https://appleid.apple.com(固定签名)(**此字段已被官方替换成 “kid” 用于找到第二步中kid匹配的keys**);
“aud”=APPID
“sub”=**用户的唯一标识**(所以前端不需要额外传递userID)

代码:

String [] identityTokens = identityToken.split(“\\.”);
Map<String, Object> data = JsonUtils.parseMap(new String(Base64.decodeBase64(identityTokens[1]),”UTF-8″),String.class, Object.class);
String iss = (String) data.get(“kid”);
String aud = (String) data.get(“aud”);
String sub = (String) data.get(“sub”);

5.将”identityToken”和上一步解析出来的”kid”,“aud”,”sub”传入一下方法验证JWT是否有效,返回true即等于没问题:

AUTH_TIME_STR = auth_time
public boolean verify(String identityToken,String iss,String aud,String sub) {
PublicKey publicKey = getPublicKey();
JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey);
jwtParser.requireIssuer(iss);
jwtParser.requireAudience(aud);
jwtParser.requireSubject(sub);
try {
Jws<Claims> claim = jwtParser.parseClaimsJws(identityToken);
if (null != claim && claim.getBody().containsKey(AUTH_TIME_STR)) {
return true;
}
return false;
} catch (ExpiredJwtException e) {
return false;
} catch (Exception e) {
return false;
}
}

6.没问题的话将userID保存数据库(本文数据库操作忽略…)

使用Apple第三方登录Java版

由IOS端传过来code

服务端代码

import java.security.KeyFactory;

import java.security.PrivateKey;

import java.security.spec.PKCS8EncodedKeySpec;

import java.util.Base64;

import java.util.Collections;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;

import com.auth0.jwt.JWT;

import com.auth0.jwt.interfaces.DecodedJWT;

import io.jsonwebtoken.Jwts;

import io.jsonwebtoken.SignatureAlgorithm;

public class AppleLoginController {

/**

* 苹果授权登录

*

* @param code

* @param subject

* @return

* @throws Exception

*/

@GetMapping(“/authCode”)

public void authCode(String code) throws Exception {
String client_id = “com.**.**”; // 被授权的APP ID

Map<String, Object> header = new HashMap<String, Object>();

header.put(“kid”, “***”); // 参考后台配置

Map<String, Object> claims = new HashMap<String, Object>();

claims.put(“iss”, “***”); // 参考后台配置 team id

long now = System.currentTimeMillis() / 1000;

claims.put(“iat”, now);

claims.put(“exp”, now + 86400 * 30); // *长半年,单位秒

claims.put(“aud”, “https://appleid.apple.com”); // 默认值

claims.put(“sub”, client_id);

PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(readKey());

KeyFactory keyFactory = KeyFactory.getInstance(“EC”);

PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

String client_secret = Jwts.builder().setHeader(header).setClaims(claims)

.signWith(SignatureAlgorithm.ES256, privateKey).compact();

String url = “https://appleid.apple.com/auth/token”;

// POST 请求

Map<String, String> params = new HashMap<String, String>();

Map<String, String> headers = new HashMap<String, String>();

headers.put(“Content-Type”, “application/x-www-form-urlencoded”);

params.put(“client_id”, client_id);

params.put(“client_secret”, client_secret);

params.put(“code”, code);

params.put(“grant_type”, “authorization_code”);

params.put(“redirect_uri”, “”);

HttpClientResult httpClientResult = HttpClientUtil.doPost(url, headers, params);

Map<String, Object> jsonObject = JSONObject.parseObject(httpClientResult.getContent());

DecodedJWT jwtString = JWT.decode(jsonObject.get(“id_token”).toString());

String sub = jwtString.getSubject();

}

private byte[] readKey() throws Exception {
String temp = “*******”;//记得去掉换行符号,密钥

return Base64.getDecoder().decode(temp);

}

}

jar包依赖

<dependency>

<groupId>io.jsonwebtoken</groupId>

<artifactId>jjwt</artifactId>

<version>0.7.0</version>

</dependency>

<!– https://mvnrepository.com/artifact/com.auth0/java-jwt –>

<dependency>

<groupId>com.auth0</groupId>

<artifactId>java-jwt</artifactId>

<version>3.10.3</version>

</dependency>

苹果APP授权登录

一、前置说明
苹果App开发完成后支持微信QQ一键登录,审核时要求具备Apple登录以防万一,苹果登录有两种方式,一种是jwt,二是授权码模式,这里采用jwt模式,开发语言为java

二、代码实现
使用相关技术:jwt+restTemplate+fastjson

/**
* 解析apple授权token
* @param jwt
* @return
* @throws Exception
*/
@Override
public JSONObject appleAuth(String jwt) throws Exception {
//解析identityToken
String[] jwtArray = jwt.split(“\\.”);
String claim = new String(Base64.decodeBase64(jwtArray[1]));
JSONObject claimJson = JSONObject.parseObject(claim);
// 解析头部 kid
String header = new String(Base64.decodeBase64(jwtArray[0]));
JSONObject headerJson = JSONObject.parseObject(header);
// 请求获取苹果公钥
String body = restTemplate.getForObject(“https://appleid.apple.com/auth/keys”,String.class);
JSONObject jsonObject = JSONObject.parseObject(body);
String keys = jsonObject.getString(“keys”);
JSONArray arr = JSONObject.parseArray(keys);
JSONObject appleKey1 = JSONObject.parseObject(arr.getString(0));
JSONObject appleKey2 = JSONObject.parseObject(arr.getString(1));
JSONObject appleKey = appleKey1;
if( !headerJson.getString(“kid”).equals(appleKey1.getString(“kid”)) ){
appleKey = appleKey2;
}
// 生成苹果公钥
BigInteger modulus = new BigInteger(1, Base64.decodeBase64(appleKey.getString(“n”)));
BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(appleKey.getString(“e”)));
RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulus, publicExponent);

//生成 PublicKey
KeyFactory kf = KeyFactory.getInstance(“RSA”);
PublicKey publicKey = kf.generatePublic(rsaPublicKeySpec);
//校验有效
return verify(publicKey,jwt,claimJson);
}

public JSONObject verify(PublicKey key, String jwt, JSONObject claimJson){
//构造返回数据
JSONObject result = new JSONObject();
boolean status = false;
//校验
JwtParser jwtParser = Jwts.parser().setSigningKey(key);
jwtParser.requireIssuer(claimJson.getString(“iss”))
.requireAudience(claimJson.getString(“aud”))
.requireSubject(claimJson.getString(“sub”));
try {
Jws<Claims> claim = jwtParser.parseClaimsJws(jwt);
if (claim != null && claim.getBody().containsKey(“auth_time”)) {
//校验成功
status = true;
//返回 用户的唯一标识
result.put(“sub”,claimJson.getString(“sub”));
}
}catch (Exception e) {
log.error(“校验失败”);
}
result.put(“status”,status);
return result;
}

苹果CMS内容管理系统 – 苹果CMS官方网站

自从苹果cms官方网站关闭后,对于刚接触的小伙伴们就已经懵逼状态了!今天我在这给大家普及下。

我们可以用百度搜索 “苹果cms” 会出现下面的页面,排在*位的就是苹果cms官网,不过现在是关站状态。具体原因下面讲。

%title插图%num

下面的几个地址是有关于苹果cms的:

①www.maccms.com/官网(现在是关闭状态)

②http://t.maccms.com/(网站关停页面)在本页面按下—-F12 会有彩蛋出现

③https://github.com/magicblack这个是苹果cms在github平台的地址,也是现在唯一更新的地址。如果你看不懂英文请用浏览器翻译下。请牢记

⑤https://www.mytheme.cn/这个是苹果cms的模板商 专业制作苹果cms模板 此行业零头衔。

④https://www.showdoc.cc/mytheme?page_id=2779989134071820这个是关于苹果cms的一些入门级使用教程。

关于苹果cms为什么会关闭,官方给出的答案是:

由于不可抗因素已于19年3月关闭,预计20年5月恢复

老王原QQ暂时无法使用,请勿联系请勿发任何信息

苹果CMS软件著作权证书号:2018SR947830,请勿非法修改发布。

cmd中检测远程的ip和端口是否处于监听状态

*步:使用ping命令测试远程的ip是否可连通

在cmd中输入ping ip地址:

%title插图%num

如果*后的统计信息中丢失率为0表示可以连通该ip地址。那么就可以进行下一步的测试该ip下的某一个端口是否开放的操作了。

第二步:使用telnet测试远程某一个ip的端口是否开放
为了安全起见,windows默认是不开启telnet客户端的,要通过控制面板—》程序–》启动或关闭windows功能—》telnet客户端—》确定

%title插图%num

安装完成telnet客户端之后,就可以在cmd中使用telnet命令了。
使用命令:telnet ip地址 端口号

如果出现下面的提示说明连接失败,端口号是未开启的,或者没有处于监听状态

%title插图%num

如果出现下面的空白界面说明连接成功,端口号是开启,并处于监听状态的

%title插图%num

 

在cmd检测端口和服务器的方法

点击左下角在输入框输入cmd,回车:
1.ping ip; 检测服务地址是否相通

2.telnet ip 端口号;检测端口号是否打开

3.netstat -anp tcp;查看当前主机tcp开放的端口

4.ipconfig 查看当前的服务器ip地址

linux系统下:右键选择 打开终端:

输入ifconfig 查看当前服务器ip地址

/etc/init.d/sshd start 打开虚拟机上的22端口

在cmd窗口下连接服务端

在cmd用MySQL连接服务端几种方式
一般来说,我们都会用到数据库做一些数据的增删查改。假如,我们在已知用户和密码的情况下连接数据库,用户名为“root”,密码“123456”。

一、连接本地数据库

C:\WINDOWS\system32>mysql -h localhost -u root -p123456

注意:“-p”和“123456” 之间不能有空格
1
二、连接本地数据库内指定的数据库,数据库名为“db”

C:\WINDOWS\system32>mysql -h 127.0.0.1 -u root -p123456 -D db

三、MySQL 连接本地数据库,可以先不输入密码,然后根据提示输入密码:

C:\WINDOWS\system32> mysql -h localhost -u root -p
Enter password:
%title插图%num

出现以上提示则输入密码后回车即可。

四、MySQL 连接远程数据库(192.168.1.10),端口“3306”,用户名为“root”,密码“123456”

C:\WINDOWS\system32>mysql -h 192.168.1.10 -P 3306 -u root -p123456

注意:这里是大写的“P”表示指明端口号。
1
我运行的cmd窗口都使用了管理员模式,密码一般为初始密码,不排除有自己修改过的可能性,所以这里的密码仅供参考。

231. 2的幂(JS实现)

231. 2的幂(JS实现)
1 题目
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
示例 1:
输入: 1
输出: true
解释: 20 = 1
示例 2:
输入: 16
输出: true
解释: 24 = 16
示例 3:
输入: 218
输出: false
链接:https://leetcode-cn.com/problems/power-of-two
2 思路
这道题用位运算*快,满足2的幂,则二进制表达只有一个1,其余全为0
3代码
/**
 * @param {number} n
 * @return {boolean}
 */
var isPowerOfTwo = function(n) {
  if (n <= 0) return false;
  return n & (n – 1) == 0;
};