Sign in with Apple(アップルライセンス登録)java jwt方式検証

5547 ワード

この記事の参考になるテキストリンク:https://blog.csdn.net/wpf199402076118/article/details/99677412
アップルライセンス登録方式
  • PC/M側ライセンス登録、プロトコル採用はoauth 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
    アップルのライセンス登録バックエンドの検証方法を重点的に説明します
    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識別、署名アルゴリズムはRS 256(RSA 256+SHA 256)を採用し、kty定数識別はRSA署名アルゴリズムを使用し、その公開鍵パラメータはnとeであり、その値はBASE 64符号化を採用し、使用時に先に復号する必要がある
    使用方法:APP内のアップルのライセンス登録には、userID、email、fullName、authorizationCode、
  • identityToken
  • userID:認証されたユーザ一意ID
  • email、fullName:承認されたユーザ資料
  • authorizationCode:承認code
  • identityToken:ユーザに許可されたJWT証明書
  • 以下、identityTokenバックエンド検証について簡単に説明します.
  • dentityToken参考例(dentityTokenはiosがバックエンドに渡され、バックエンドもこのjwt列しか使われなかった):
  • // jwt   (  jwt  ios    )
    eyJraWQiOiJBSURPUEsxIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLnNreW1pbmcuZGV2aWNlbW9uaXRvciIsImV4cCI6MTU2NTY2ODA4NiwiaWF0IjoxNTY1NjY3NDg2LCJzdWIiOiIwMDEyNDcuOTNiM2E3OTlhN2M4NGMwY2I0NmNkMDhmMTAwNzk3ZjIuMDcwNCIsImNfaGFzaCI6Ik9oMmFtOWVNTldWWTNkcTVKbUNsYmciLCJhdXRoX3RpbWUiOjE1NjU2Njc0ODZ9.e-pdwK4iKWErr_Gcpkzo8JNi_MWh7OMnA15FvyOXQxTx0GsXzFT3qE3DmXqAar96nx3EqsHI1Qgquqt2ogyj-lLijK_46ifckdqPjncTEGzVWkNTX8uhY7M867B6aUnmR7u-cf2HsmhXrvgsJLGp2TzCI3oTp-kskBOeCPMyTxzNURuYe8zabBlUy6FDNIPeZwZXZqU0Fr3riv2k1NkGx5MqFdUq3z5mNfmWbIAuU64Z3yKhaqwGd2tey1Xxs4hHa786OeYFF3n7G5h-4kQ4lf163G6I5BU0etCRSYVKqjq-OL-8z8dHNqvTJtAYanB3OHNWCHevJFHJ2nWOTT3sbw
    

    検証方法
    アップルのログインを検証するのは主にios側からバックエンドに渡されたjwt列を通じて有効期間内であるかどうかを検証する.
  • アップルに要求された公開鍵インタフェースはいくつかのパラメータを返しますが、主に2つのパラメータnとeでpublicKeyをjwt署名としてjwtを解くことを算出します
  • ではnとeでpublicKeyを算出するためにツールクラスhutoolを使用した(パッケージが便利で三者依存は不要)
  • hutoolとjwtを導入したmaven依存
  •         
                cn.hutool
                hutool-all
                4.5.16
            
            
                io.jsonwebtoken
                jjwt
                0.6.0
            
    

    次にhutoolを使用
            //n          n 
           String n="lxrwmuYSAsTfn-lUu4goZSXBD9ackM9OJuwUVQHmbZo6GW4Fu_auUdN5zI7Y1dEDfgt7m7QXWbHuMD01HLnD4eRtY-RNwCWdjNfEaY_esUPY3OVMrNDI15Ns13xspWS3q-13kdGv9jHI28P87RvMpjz_JCpQ5IM44oSyRnYtVJO-320SB8E2Bw92pmrenbp67KRUzTEVfGU4-obP5RZ09OxvCr1io4KJvEOjDJuuoClF66AT72WymtoMdwzUmhINjR0XSqK6H0MdWsjw7ysyd_JhmqX5CAaT9Pgi0J8lU_pcl215oANqjy7Ob-VMhug9eGyxAWVfu_1u6QJKePlE-w";
           //e          e 
           String e="AQAB";
           //       n e base64   ,  import cn.hutool.core.codec.Base64Decoder ,  base64   
           byte[] nDecode = Base64Decoder.decode(n.getBytes());
           byte[] eDecode = Base64Decoder.decode(e.getBytes());
           //  RSAPublicKeySpec       
           RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(new BigInteger(1, nDecode), new BigInteger(1, eDecode));
           //  hutool      publicKey   import cn.hutool.crypto.SecureUtil;
           PublicKey publicKey = SecureUtil.generatePublicKey("RSA", rsaPublicKeySpec);
           //ios     jwt 
           String jwt="eyJraWQiOiJBSURPUEsxIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLnNreW1pbmcuZGV2aWNlbW9uaXRvciIsImV4cCI6MTU2NTY2ODA4NiwiaWF0IjoxNTY1NjY3NDg2LCJzdWIiOiIwMDEyNDcuOTNiM2E3OTlhN2M4NGMwY2I0NmNkMDhmMTAwNzk3ZjIuMDcwNCIsImNfaGFzaCI6Ik9oMmFtOWVNTldWWTNkcTVKbUNsYmciLCJhdXRoX3RpbWUiOjE1NjU2Njc0ODZ9.e-pdwK4iKWErr_Gcpkzo8JNi_MWh7OMnA15FvyOXQxTx0GsXzFT3qE3DmXqAar96nx3EqsHI1Qgquqt2ogyj-lLijK_46ifckdqPjncTEGzVWkNTX8uhY7M867B6aUnmR7u-cf2HsmhXrvgsJLGp2TzCI3oTp-kskBOeCPMyTxzNURuYe8zabBlUy6FDNIPeZwZXZqU0Fr3riv2k1NkGx5MqFdUq3z5mNfmWbIAuU64Z3yKhaqwGd2tey1Xxs4hHa786OeYFF3n7G5h-4kQ4lf163G6I5BU0etCRSYVKqjq-OL-8z8dHNqvTJtAYanB3OHNWCHevJFHJ2nWOTT3sbw";
           //import io.jsonwebtoken.Jwts; jwt,publicKey    
           Claims body = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(jwt).getBody();
    

    このとき上記のjwt値で実行すると投げ出されます:io.jsonwebtoken.ExpiredJwtException: JWT expired at 2019-08-13T11:48:06+0800. Current time: 2019-12-17T12:14:49+0800このjwtが期限切れであることを説明し、この異常を自分でcatchでフロントエンドにcodeとmessageを返すことができます
  • リアルjwtストリングで解く場合はbody.getSubject()を使用してユーザの一意の識別子を取得できる