Sign around us. With more rules existing,signs are becoming common to everybody. It is easy for

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sign around us. With more rules existing,signs are becoming common to everybody. It is easy for相关的知识,希望对你有一定的参考价值。

Sign around us.
With more rules existing,signs are becoming common to everybody.
It is easy for us to find the "no somoking" signs on the underground and in theatres.
Moreover,there are signs stand for different directions on the road and distinct bans for every circumstance.
For example,there may be a "throw in" sign beside a rubbish bin,and a "dangerous" sign on the side of a deep swimming pool.
Signs around us are important because they tell us what we should or shouldn't do at the moment.
Every citizen is obliged to obey signs around us.

Sign around us.
我们周围的迹象。
With more rules existing,signs are becoming common to everybody.
与现有更多的规则,每个人都越来越常见的迹象。
It is easy for us to find the "no somoking" signs on the underground and in theatres.
对我们来说很容易找到“没有somoking”迹象在地下和剧院而著名。
Moreover,there are signs stand for different directions on the road and distinct bans for every circumstance.
此外,有迹象显示,代表不同的方向在路上每个环境和不同的禁令。
For example,there may be a "throw in" sign beside a rubbish bin,and a "dangerous" sign on the side of a deep swimming pool.
例如,可能有一个“扔”标志在一个垃圾桶旁边,和一个“危险”标志的游泳池。
Signs around us are important because they tell us what we should or shouldn't do at the moment.
我们周围的迹象很重要,因为他们告诉我们我们应该或不应该做什么。
Every citizen is obliged to obey signs around us.
每个公民都有义务遵守我们周围的迹象。
参考技术A 在我们周围签名。

随着越来越多的规则存在,迹象变得越来越常见。

我们很容易找到“禁止抽烟”在地下,在剧院的迹象。

此外,有迹象表明道路上的不同方向和不同的禁令的每一个情况。

例如,有可能是一个“扔”在一个垃圾桶旁边的标志,和一个“危险”的标志在一个深游泳池旁边。

我们周围的迹象是重要的,因为他们告诉我们,我们应该或不应该做的时刻。

每个公民都有义务遵守我们周围的标志。

C# Sign In With Apple苹果登陆后端验证

苹果App授权登录

苹果官方的授权文档:

生成Token:https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens
JWT:https://developer.apple.com/documentation/sign_in_with_apple/fetch_apple_s_public_key_for_verifying_token_signature

苹果的授权登录

APP内苹果授权登陆会提供如下几个参数:userID、email、fullName、authorizationCode、identityToken
userID:授权的用户唯一标识
email、fullName:授权的用户资料
authorizationCode:授权code
identityToken:授权用户的JWT凭证

针对后端验证苹果提供了两种验证方式,一种是基于JWT的算法验证,另外一种是基于授权码的验证

JWT验证

identityToken参考:

技术图片
 1 // jwt 格式
 2 eyJraWQiOiJBSURPUEsxIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLnNreW1pbmcuZGV2aWNlbW9uaXRvciIsImV4cCI6MTU2NTY2ODA4NiwiaWF0IjoxNTY1NjY3NDg2LCJzdWIiOiIwMDEyNDcuOTNiM2E3OTlhN2M4NGMwY2I0NmNkMDhmMTAwNzk3ZjIuMDcwNCIsImNfaGFzaCI6Ik9oMmFtOWVNTldWWTNkcTVKbUNsYmciLCJhdXRoX3RpbWUiOjE1NjU2Njc0ODZ9.e-pdwK4iKWErr_Gcpkzo8JNi_MWh7OMnA15FvyOXQxTx0GsXzFT3qE3DmXqAar96nx3EqsHI1Qgquqt2ogyj-lLijK_46ifckdqPjncTEGzVWkNTX8uhY7M867B6aUnmR7u-cf2HsmhXrvgsJLGp2TzCI3oTp-kskBOeCPMyTxzNURuYe8zabBlUy6FDNIPeZwZXZqU0Fr3riv2k1NkGx5MqFdUq3z5mNfmWbIAuU64Z3yKhaqwGd2tey1Xxs4hHa786OeYFF3n7G5h-4kQ4lf163G6I5BU0etCRSYVKqjq-OL-8z8dHNqvTJtAYanB3OHNWCHevJFHJ2nWOTT3sbw
 3  
 4 // header 解码
 5 {"kid":"AIDOPK1","alg":"RS256"} 其中kid对应上文说的密钥id
 6  
 7 // claims 解码
 8 {
 9 "iss":"https://appleid.apple.com",
10 "aud":"com.skyming.devicemonitor",
11 "exp":1565668086,"iat":1565667486,
12 "sub":"001247.93b3a799a7c84c0cb46cd08f100797f2.0704",
13 "c_hash":"Oh2am9eMNWVY3dq5JmClbg",
14 "auth_time":1565667486
15 }
16  
17 ss标识是苹果签发的,aud是接收者的APP ID,sub就是用户的唯一标识
View Code

解析的sub和前端传过来的比较是否一致;

基于授权码的后端验证

创建Secret

技术图片
private string CreateSecret()
        {

            var handler = new JwtSecurityTokenHandler();
            var subject = new Claim("sub", Client_Id);//找IOS要 
            var tokenDescriptor = new SecurityTokenDescriptor()
            {
                Audience = "https://appleid.apple.com",//固定值
                Issuer = Team_Id,//team ID,找IOS要                                 
                IssuedAt = DateTime.Now.AddDays(-1),
                NotBefore = DateTime.Now.AddDays(-1),
                Subject = new ClaimsIdentity(new[] { subject }),
            };

            var algorithm = new ECDsaCng(GetPrivateKey());
            {
                tokenDescriptor.SigningCredentials = CreateSigningCredentials(Key_Id, algorithm);//p8私钥文件得Key,找IOS要
                var clientSecret = handler.CreateEncodedJwt(tokenDescriptor);
                return clientSecret;
            }

        }
View Code
技术图片
        /// <summary>
        /// 获取P8
        /// </summary>
        /// <returns></returns>
        private CngKey GetPrivateKey()
        {
            using (var reader = new StringReader("p8文件内容"))
            {
                var ecPrivateKeyParameters = (ECPrivateKeyParameters)new PemReader(reader).ReadObject();
                var x = ecPrivateKeyParameters.Parameters.G.AffineXCoord.GetEncoded();
                var y = ecPrivateKeyParameters.Parameters.G.AffineYCoord.GetEncoded();
                var d = ecPrivateKeyParameters.D.ToByteArrayUnsigned();
                return EccKey.New(x, y, d);
            }
        }
View Code

参考文献:https://stackoverflow.com/questions/42514289/how-to-use-apns-auth-key-p8-file-in-c

网上还有另外一种P8文件的内容

技术图片
     private static ECDsa GetPrivateKey()
        {
            CngKey privateKey = null;

            //p8文件内容
            string content = @"-----BEGIN PRIVATE KEY-----
                              ****
                              -----END PRIVATE KEY-----";

            // 这里直接用去头去尾的方法:
            var lines = content.Split(
);
            var trimmed = string.Join("", lines.Skip(1).Take(lines.Length - 2).Select(l => l.Trim()));
            var keyBlob = Convert.FromBase64String(trimmed);

            _Log.Info("test1");

            privateKey = CngKey.Import(keyBlob, CngKeyBlobFormat.Pkcs8PrivateBlob, CngProvider.MicrosoftSoftwareKeyStorageProvider);

            _Log.Info("test2");


            return new ECDsaCng(privateKey);
        }
View Code

这是一个坑深坑:

本地调试没问题,发布到服务器上就报错:System.Security.Cryptography.CryptographicException: 系统找不到指定的文件。

度娘个的解决方案就是:在服务器上的IIS修改一些配置。(ex:服务能随便改配置吗?万一把其他接口搞挂了呢);

根据生成的Secret和授权码AuthorizationCode来验证是否正确

技术图片
var newToken = CreateSecret();
                var datas = new Dictionary<string, string>()
                {
                    { "client_id", Client_Id },
                    { "grant_type", "authorization_code"},//固定authorization_code
                    { "code", authLoginModel.AuthorizationCode },//授权码,前端验证登录给予 
                    { "client_secret", newToken } //client_secret,后面方法生成
                };

                var formdata = new FormUrlEncodedContent(datas);
                using (var httpclient = new HttpClient())
                {
                    httpclient.Timeout = TimeSpan.FromSeconds(30);
                    var result = await httpclient.PostAsync(Apple_Token_Url, formdata);
                    var re = await result.Content.ReadAsStringAsync();
                    if (result.IsSuccessStatusCode)
                    {
                        var deserializeObject = JsonConvert.DeserializeObject<AppleTokenResult>(re);
                        var jwtPlayload = DecodeJwtPlayload(deserializeObject.IdToken);
                        if (jwtPlayload.Aud.Equals(Client_Id) && !string.IsNullOrEmpty(jwtPlayload.Sub))
                        {
                            appleUserId = jwtPlayload.Sub;
                        }
                    }
                    else
                    {
                        return OperationResult.FromError<AuthLoginBindResponse>($"{(int)BizCodeEnum.SING_FAIL}", re);
                    }
                }
View Code

验证成功后会返回

技术图片
{
"access_token":"a0996b16cfb674c0eb0d29194c880455b.0.nsww.5fi5MVC-i3AVNhddrNg7Qw",
"token_type":"Bearer",
"expires_in":3600,
"refresh_token":"r9ee922f1c8b048208037f78cd7dfc91a.0.nsww.KlV2TeFlTr7YDdZ0KtvEQQ",
"id_token":"eyJraWQiOiJBSURPUEsxIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLnNreW1pbmcuYXBwbGVsb2dpbmRlbW8iLCJleHAiOjE1NjU2NjU1OTQsImlhdCI6MTU2NTY2NDk5NCwic3ViIjoiMDAwMjY2LmRiZTg2NWIwYWE3MjRlMWM4ODM5MDIwOWI5YzdkNjk1LjAyNTYiLCJhdF9oYXNoIjoiR0ZmODhlX1ptc0pqQ2VkZzJXem85ZyIsImF1dGhfdGltZSI6MTU2NTY2NDk2M30.J6XFWmbr0a1hkJszAKM2wevJF57yZt-MoyZNI9QF76dHfJvAmFO9_RP9-tz4pN4ua3BuSJpUbwzT2xFD_rBjsNWkU-ZhuSAONdAnCtK2Vbc2AYEH9n7lB2PnOE1mX5HwY-dI9dqS9AdU4S_CjzTGnvFqC9H5pt6LVoCF4N9dFfQnh2w7jQrjTic_JvbgJT5m7vLzRx-eRnlxQIifEsHDbudzi3yg7XC9OL9QBiTyHdCQvRdsyRLrewJT6QZmi6kEWrV9E21WPC6qJMsaIfGik44UgPOnNnjdxKPzxUAa-Lo1HAzvHcAX5i047T01ltqvHbtsJEZxAB6okmwco78JQA"
}
View Code

其中id_token就是JWT文件,然后对JWT文件进行解析

技术图片
    /// <summary>
        /// 解析jwt第二部分
        /// </summary>
        /// <param name="jwtString"></param>
        /// <returns></returns>
        private JwtPlayloadModel JwtPlayload(string jwtString)
        {
            try
            {
                var code = jwtString.Split(.)[1];
                code = code.Replace(-, +).Replace(_, /).PadRight(4 * ((code.Length + 3) / 4), =);
                var bytes = Convert.FromBase64String(code);
                var decode = Encoding.UTF8.GetString(bytes);
                return JsonConvert.DeserializeObject<JwtPlayloadModel>(decode);
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }
View Code

以上是关于Sign around us. With more rules existing,signs are becoming common to everybody. It is easy for的主要内容,如果未能解决你的问题,请参考以下文章

Array types are now written with the brackets around the element type问题的解决方法

C# Sign In With Apple苹果登陆后端验证

Android Sign in with apple and firebase flutter

为 android 配置 Flutter“sign_in_with_apple”时出现问题

Sign in with Apple(苹果授权登陆)服务端验证

使用 Apple 登录按钮标题始终显示“SIGN_IN_WITH_APPLE”