• 1006 Sign In and Sign Out 原题 思路 考虑以结构体存放整体 比较函数time，用于比较两个变量中的时间大小，采用时、分、秒依次比较的方法，返回值为bool 关键在于找到最小签到时间和最大签离时间，要注意...
1006 Sign In and Sign Out
原题    思路
考虑以结构体存放整体比较函数time，用于比较两个变量中的时间大小，采用时、分、秒依次比较的方法，返回值为bool关键在于找到最小签到时间和最大签离时间，要注意比较之前分别把比较的初始值设成最大和最小,否则可能导致最终得出的结果不存在或有误  题解
#include<stdio.h>
#include<iostream>
#include<cstring>
using namespace std;
struct user{
string id;
int hour,min,second;
};
bool time(user user1,user user2)//user1的时间大于user2的时间则返回true
{
if(user1.hour!=user2.hour)
return user1.hour >user2.hour;
if(user1.min!=user2.min)
return user1.min>user2.min;
return user1.second>user2.second;
}
int main()
{
int m;
cin>>m;

struct user users[2],t;
users[0].hour=24,users[0].min=60,users[0].second=60;//把初始签到时间设成最大
users[1].hour=0,users[1].min=0;users[1].second=0;//把初始签离时间设成最小
for(int i=0;i<m;i++)
{
cin>>t.id;
scanf("%d:%d:%d",&t.hour,&t.min,&t.second);
if(time(t,users[0])==false) users[0]=t;//取更小的签到时间

scanf("%d:%d:%d",&t.hour,&t.min,&t.second);
if(time(t,users[1])==true) users[1]=t;//取更大的签离时间
}

cout<<users[0].id<<' '<<users[1].id;
return 0;
}

展开全文
• 1006 Sign In and Sign Out (25分) At the beginning of every day, the first person who signs in the computer room will unlock the door, and the last one who signs out will lock the door. Given the reco...

At the beginning of every day, the first person who signs in the computer room will unlock the door, and the last one who signs out will lock the door. Given the records of signing in's and out's, you are supposed to find the ones who have unlocked and locked the door on that day.
Input Specification:
Each input file contains one test case. Each case contains the records for one day. The case starts with a positive integer M, which is the total number of records, followed by M lines, each in the format:
ID_number Sign_in_time Sign_out_time


where times are given in the format HH:MM:SS, and ID_number is a string with no more than 15 characters.
Output Specification:
For each test case, output in one line the ID numbers of the persons who have unlocked and locked the door on that day. The two ID numbers must be separated by one space.
Note: It is guaranteed that the records are consistent. That is, the sign in time must be earlier than the sign out time for each person, and there are no two persons sign in or out at the same moment.
Sample Input:
3
CS301111 15:30:28 17:00:10
SC3021234 08:00:00 11:25:25
CS301133 21:45:00 21:58:40


Sample Output:
SC3021234 CS301133

一、存储结构
每个个体有id、登录时间（in）、登出时间（out）三个变量，所以我们通过结构体储存。
并且声明三个结构体变量：
temp：处理输入的个体，暂时储存
unlocked：储存当下登入时间最早的个体
locked：储存当下登出时间最晚的个体

二、具体算法
比较时间先后：直接利用 "cstring" 库中的 strcmp 函数进行比较即可。

对于输入的数据，暂时存储在结构体变量temp中。
然后通过比较对应的时间，更新unlocked和locked变量。

三、注意
1、locked和unlucked的初值要想清楚
2、清楚字符串比较函数 strcmp（str1, str2）的返回值：
当str1 > str2，返回一个正数（注意不一定是1）    当str1 = str2，返回整数0    当str1 < str2，返回一个负数（注意不一定是-1）

具体代码如下：
//
// Created by LittleCat on 2020/1/31.
//

#include <cstdio>
#include <cstring>

struct person {
char id[16];
char in[16];
char out[16];
} temp, unlocked, locked;

int main() {

strcpy(unlocked.in, "24:00:00");
strcpy(locked.out, "00:00:00");

int t;
for(scanf("%d", &t); t; t--) {
scanf("%s %s %s", temp.id, temp.in, temp.out);
if(strcmp(temp.in, unlocked.in) < 0)
unlocked = temp;
if(strcmp(temp.out, locked.out) > 0)
locked = temp;
}

printf("%s %s\n", unlocked.id, locked.id);
}



end
欢迎关注个人公众号“鸡翅编程”，这里是认真且乖巧的码农一枚，旨在用心写好每一篇文章，平常会把笔记汇总成推送更新~

展开全文
• ## Signin with Apple（苹果授权登陆）

万次阅读 热门讨论 2019-08-16 14:31:02
苹果授权登陆方式 ... 开发者后台配置 详细配置参考该文档，手把手教学 https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple 1、 PC/M接入方式 https://appleid.app...
苹果授权登陆方式
1. PC/M端授权登陆，采用协议类似于oauth2协议 2. App端授权登陆，提供两种后端验证方式
开发者后台配置
详细配置参考该文档，手把手教学 https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple
1、 PC/M接入方式
https://appleid.apple.com/auth/authorize?response_type=code&client_id=&redirect_uri=&state=1234参考上面的后台配置，其中client_id对应的是Services ID，redirect_uri就是后台配置的接收code码的地址
2、APP端客户端授权登陆功能开发，可以参考如下文档
https://www.jianshu.com/p/23b46dea2076
重点讲解苹果授权登陆后端如何验证
针对后端验证苹果提供了两种验证方式，一种是基于JWT的算法验证，另外一种是基于授权码的验证
1、基于JWT的算法验证
使用到的Apple公钥接口：https://appleid.apple.com/auth/keys详细接口文档说明参见：https://developer.apple.com/documentation/signinwithapplerestapi/fetch_apple_s_public_key_for_verifying_token_signature接口返回值：
{
"keys": [
{
"kty": "RSA",
"kid": "AIDOPK1",
"use": "sig",
"alg": "RS256",
"n": "lxrwmuYSAsTfn-lUu4goZSXBD9ackM9OJuwUVQHmbZo6GW4Fu_auUdN5zI7Y1dEDfgt7m7QXWbHuMD01HLnD4eRtY-RNwCWdjNfEaY_esUPY3OVMrNDI15Ns13xspWS3q-13kdGv9jHI28P87RvMpjz_JCpQ5IM44oSyRnYtVJO-320SB8E2Bw92pmrenbp67KRUzTEVfGU4-obP5RZ09OxvCr1io4KJvEOjDJuuoClF66AT72WymtoMdwzUmhINjR0XSqK6H0MdWsjw7ysyd_JhmqX5CAaT9Pgi0J8lU_pcl215oANqjy7Ob-VMhug9eGyxAWVfu_1u6QJKePlE-w",
"e": "AQAB"
}
]
}
kid，为密钥id标识，签名算法采用的是RS256（RSA 256 + SHA 256），kty常量标识使用RSA签名算法，其公钥参数为n和e，其值采用了BASE64编码，使用时需要先解码
使用方式：APP内苹果授权登陆会提供如下几个参数：userID、email、fullName、authorizationCode、identityToken
userID：授权的用户唯一标识email、fullName：授权的用户资料authorizationCode：授权code identityToken：授权用户的JWT凭证
下面针对identityToken后端验证做简要说明：
identityToken参考样例：
// jwt 格式
eyJraWQiOiJBSURPUEsxIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLnNreW1pbmcuZGV2aWNlbW9uaXRvciIsImV4cCI6MTU2NTY2ODA4NiwiaWF0IjoxNTY1NjY3NDg2LCJzdWIiOiIwMDEyNDcuOTNiM2E3OTlhN2M4NGMwY2I0NmNkMDhmMTAwNzk3ZjIuMDcwNCIsImNfaGFzaCI6Ik9oMmFtOWVNTldWWTNkcTVKbUNsYmciLCJhdXRoX3RpbWUiOjE1NjU2Njc0ODZ9.e-pdwK4iKWErr_Gcpkzo8JNi_MWh7OMnA15FvyOXQxTx0GsXzFT3qE3DmXqAar96nx3EqsHI1Qgquqt2ogyj-lLijK_46ifckdqPjncTEGzVWkNTX8uhY7M867B6aUnmR7u-cf2HsmhXrvgsJLGp2TzCI3oTp-kskBOeCPMyTxzNURuYe8zabBlUy6FDNIPeZwZXZqU0Fr3riv2k1NkGx5MqFdUq3z5mNfmWbIAuU64Z3yKhaqwGd2tey1Xxs4hHa786OeYFF3n7G5h-4kQ4lf163G6I5BU0etCRSYVKqjq-OL-8z8dHNqvTJtAYanB3OHNWCHevJFHJ2nWOTT3sbw

{"kid":"AIDOPK1","alg":"RS256"} 其中kid对应上文说的密钥id

// claims 解码
{
"iss":"https://appleid.apple.com",
"aud":"com.skyming.devicemonitor",
"exp":1565668086,"iat":1565667486,
"sub":"001247.93b3a799a7c84c0cb46cd08f100797f2.0704",
"c_hash":"Oh2am9eMNWVY3dq5JmClbg",
"auth_time":1565667486
}

其中 iss标识是苹果签发的，aud是接收者的APP ID，该token的有效期是10分钟，sub就是用户的唯一标识
如何验证？
首先通过identityToken中的header中的kid，然后结合苹果获取公钥的接口，拿到相应的n和e的值，然后通过下面这个方法构建RSA公钥

public RSAPublicKeySpec build(String n, String e) {
BigInteger modulus = new BigInteger(1, Base64.decodeBase64(n));
BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(e));
return new RSAPublicKeySpec(modulus, publicExponent);
}

通过下面这个方法验证JWT的有效性
public int verify(PublicKey key, String jwt, String audience, String subject) {
JwtParser jwtParser = Jwts.parser().setSigningKey(key);
jwtParser.requireIssuer("https://appleid.apple.com");
jwtParser.requireAudience(audience);
jwtParser.requireSubject(subject);
try {
Jws<Claims> claim = jwtParser.parseClaimsJws(jwt);
if (claim != null && claim.getBody().containsKey("auth_time")) {
return GlobalCode.SUCCESS;
}
return GlobalCode.THIRD_AUTH_CODE_INVALID;
} catch (ExpiredJwtException e) {
log.error("apple identityToken expired", e);
return GlobalCode.THIRD_AUTH_CODE_INVALID;
} catch (Exception e) {
log.error("apple identityToken illegal", e);
return GlobalCode.FAIL_ILLEGAL_REQ;
}
}

使用的JWT工具库为：
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2、基于授权码的后端验证
首先需要了解如何构建client_secret，详细文档可以参考如下两个：https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-applehttps://developer.apple.com/documentation/signinwithapplerestapi/generate_and_validate_tokens
首先说下client_secret的构建方法：
先在后台生成授权应用APP ID的密钥KEY文件，然后下载密钥文件格式样例：

-----BEGIN PRIVATE KEY-----
BASE64编码后的密钥
-----END PRIVATE KEY-----

public  byte[] readKey() throws Exception {
String temp = "密钥文件中间的编码字符串";
return Base64.decodeBase64(temp);
}

构建client_secret关键代码：

String client_id = "..."; // 被授权的APP ID
Map<String, Object> header = new HashMap<String, Object>();
Map<String, Object> claims = new HashMap<String, Object>();
claims.put("iss", "team id"); // 参考后台配置 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);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

如何验证？
String url = "https://appleid.apple.com/auth/token";
// POST 请求
HttpSynClient client = new HttpSynClient(5000, 5000, 5000, 20);
Map<String, String> form = new HashMap<String, String>();
form.put("client_id", client_id);
form.put("client_secret", client_secret);
form.put("code", code);form.put("grant_type","authorization_code");
form.put("redirect_uri", redirectUrl);
HttpResponse result = client.excutePost(url, form);
System.out.println(result);
返回值样例：
{
"access_token":"a0996b16cfb674c0eb0d29194c880455b.0.nsww.5fi5MVC-i3AVNhddrNg7Qw",
"token_type":"Bearer",
"expires_in":3600,
"refresh_token":"r9ee922f1c8b048208037f78cd7dfc91a.0.nsww.KlV2TeFlTr7YDdZ0KtvEQQ",
}
其中id_token是一个JWT，其中claims中的sub就是授权的用户唯一标识，该token也可以使用上述的验证方法进行有效性验证，另外授权code是有时效性的，且使用一次即失效
扩展资料
JWT：https://www.cnblogs.com/softidea/p/7041532.html ECDSA 椭圆曲线签名，JDK 1.7 的第四个版本提供了对ECDSA的支持：https://blog.csdn.net/qq_35612816/article/details/78904225


展开全文
链接
HBuilderX 自 2.4.7+ 版本开始支持 Sign in with Apple （苹果登录），苹果登录是 iOS13 新增加的功能，当你的应用使用了第三方登录比如微信登录，同时也需要集成苹果登录，否则提交AppStore审核会被拒绝。

根据苹果审核指南要求，如果 app 使用第三方或社交登录服务 (例如，Facebook 登录、Google 登录、通过 Twitter 登录、通过 LinkedIn 登录、通过 Amazon 登录或微信登录) 来对其进行设置或验证这个 app 的用户主帐户，则该 app 必须同时提供“通过 Apple 登录”作为同等选项。详情参考：App Store 审核指南 - 通过 Apple 登录

使用苹果登录的教程
使用苹果登录首先需要在苹果开发者后台开启 App 的 Sign In with Apple 服务

...