flutter -- 一鍵登錄(根據流量獲取手機號碼)

一鍵登陸完全簡化了用戶的操做流程,傳統要輸入手機號,而後點擊發送驗證碼,再點擊登陸,使用一鍵登陸就不用輸入手機號,直接用本機號碼登陸。php

這裏咱們使用極光的一鍵登陸【我沒收極光的錢哈】html

準備材料

申請bundle ID

進入開發者蘋果平臺,申請開發者,一年須要688人民幣,而後申請bundle id,也叫應用id,具體根據提示來,不知道的就搜一下,而後把bundle ID複製下來,粘貼到xcode裏面。java

申請應用

進入開發者平臺極光開發者平臺 申請帳號後建立應用 node

審覈經過後,點擊應用設置
設置安卓和ios信息
保存以下信息

安裝環境

插件引用

pubspec.yamlpython

dependencies:
  jverify: 0.4.0
複製代碼

安卓配置

\android\app\build.gradleandroid

defaultConfig下面添加以下代碼ios

ndk {
            //選擇要添加的對應 cpu 類型的 .so 庫。
            abiFilters 'armeabi', 'armeabi-v7a', 'x86', 'x86_64', 'mips', 'mips64', 'arm64-v8a'     
        }
        manifestPlaceholders = [
            JPUSH_PKGNAME : applicationId,
            JPUSH_APPKEY : "e579470dae40f090f92c1f3f", // NOTE: JPush 上註冊的包名對應的 Appkey.
            JPUSH_CHANNEL : "developer-default", //暫時填寫默認值便可.
        ]
複製代碼

IOS配置

無需配置git

使用

引入插件

import 'package:jverify/jverify.dart';
複製代碼

初始化

jverify.setDebugMode(true);
jverify.setup(
  appKey: "申請的appkey", 
  channel: "devloper-default"
);
複製代碼

網絡校驗

jverify.checkVerifyEnable().then((map){
      bool result = map["result"];
      if(result){
        // 當前網絡環境支持認證
        print('當前網絡環境支持認證');
      }else{
        // 當前網絡環境不支持認證
        print('no~~當前網絡環境不支持認證');
      }
    });
複製代碼

獲取loginAuth

JVUIConfig uiConfig = JVUIConfig();
jverify.setCustomAuthorizationView(false, uiConfig, landscapeConfig: uiConfig, widgets: widgetList);
    /// 步驟 2: 添加 loginAuth 接口回調的監聽 (若是想經過 loginAuth 接口異步返回獲取接口數據,則忽略此步驟)
    jverify.addLoginAuthCallBackListener((event){
      print("經過添加監聽,獲取到 loginAuth 接口返回數據,code=${event.code},message = ${event.message},operator = ${event.operator}");
    });
    /// 步驟 3:開始調用一鍵登陸接口        
    jverify.loginAuth(true).then((map){
      /// 步驟 4:獲取 loginAuth 接口異步返回數據(若是是經過添加 JVLoginAuthCallBackListener 監聽來獲取返回數據,則忽略此步驟)
      // print("經過接口異步返回,獲取到 loginAuth 接口返回數據,code=$code,message = $content,operator = $operator");
      print("經過接口異步返回,獲取到 loginAuth");
      print(map);
    });
複製代碼

(上面widgets,不是必傳參數)
在這裏,步驟三的數據纔是咱們須要的。github

getToken (目前在一鍵登錄用不到,作安全校驗的時候纔用到)

jverify.getToken().then((map){
          int _code = map["code"]; // 返回碼,2000表明獲取成功,其餘爲失敗,詳見錯誤碼描述
          String _token = map["content"]; // 成功時爲token,可用於調用驗證手機號接口。token有效期爲1分鐘,超過期效須要從新獲取才能使用。失敗時爲失敗信息
          String _operator = map["operator"]; // 成功時爲對應運營商,CM表明中國移動,CU表明中國聯通,CT表明中國電信。失敗時可能爲null
          print("一鍵登陸 token code: ${_code} 運營商: ${_operator} _token: ${_token}");
          if(_code == 2000){
                // 請求後臺校驗
          }else{
            print('沒有手機卡,或者異常');
          }
        });
複製代碼

運行邏輯web

Jverify jverify = new Jverify();
// 是否調試模式
jverify.setDebugMode(true);
// ios使用的參數
jverify.setup(
  appKey: "e57947打碼c1f3f", 
  channel: "devloper-default",
  useIDFA: false
);
jverify.checkVerifyEnable().then((map){
      bool result = map["result"];
      if(result){
        // 獲取loginAuth
        loginAuth() // 這部分的代碼就是上面 獲取loginAuth 的代碼
      }
})

複製代碼

效果

所有沒有報錯的話就是成功了

會有一個界面彈出來

點擊登陸的按鈕,就會執行

jverify.loginAuth(true)
複製代碼

這個的異步回調,數據打印出來是以下所示

調用後會自動全屏,不須要引入view到flutter界面裏面渲染

異常狀況處理

異常1

有一個安卓手機跑起來後是這樣,出問題了,QAQ

信號太差了,會有失敗的可能性,請在4G+網絡下測試。

異常2

2010

緣由: takget sdk 版本>22須要動態申請權限。
不過,咱們先申請下靜態權限 在Android/app/src/main/AndroidManifest.xml加以下代碼。(manifest裏面,application以前)

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
複製代碼

最好加下基本的權限

<uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!-- 用於開啓 debug 版本的應用在6.0 系統上 層疊窗口權限 -->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
複製代碼

而後修改Android/app/src/build.gradle (這是不能保證徹底沒問題,最好是使用動態申請權限,不過測試的時候能夠這樣作)

targetSdkVersion 22
複製代碼

動態申請權限須要寫安卓和iOS兩個權限的代碼而後封裝給flutter使用,不過有現成的插件flutter動態申請權限插件

異常3

4033

I/flutter (11895): {code: 4033, message: appkey is not support login, operator: null}
複製代碼

沒有權限,有點奇怪,我什麼都明明申請了啊

這裏忽略了一個細節,在[應用設置] -> [認證設置] -> [一鍵登錄], 如圖,申請RSA加密,把公鑰複製上去,以前咱們講了支付寶支付,裏面也是同樣的邏輯。

而後提交審覈,經過以後再試。

IOS bundle Id設置

ios xocde bundle設置

ios跑的時候須要先在xcode輸入bundle ID,不過可能會出現以下錯誤

(這個錯誤根據提示錯誤處理,沒有iOS經驗還真很差處理,其實這個不須要管它,只要保證Xcode登錄的帳號和開發者一致就行,而後bundle id沒複製錯,這時候鏈接上手機,就能夠了)

後端獲取手機號

有兩個api,一個是驗證,一個登陸驗證。

區別就是,第一個是校驗身份,目前不在咱們的使用範圍呢,也就是安全認證,好比作支付功能,教程目前使用的是是否是本人,就不能發生驗證碼,直接校驗當前使用的手機是否是登陸的帳號便可。

第二個就是咱們要用的 文檔上有一個curl

curl --insecure -X POST -v https://api.verification.jpush.cn/v1/web/loginTokenVerify -H "Content-Type: application/json" -u "7d431e42dfa6a6d693ac2d04:5e987ac6d2e04d95a9d8f0d1" -d '{"loginToken":"STsid0000001542695429579Ob28vB7b0cYTI9w0GGZrv8ujUu05qZvw","exID":"1234566"}'
複製代碼

看不懂curl沒關係,有一個文章能夠學習下。 curl教程
還有一個是吧,curl轉成語言的網址,直接生成代碼 curl轉各個語言代碼, 目前支持蠻多的,nodejs 、java、go、dart、php等

只有根據上面的獲取到了phone的密文才能解析,直接解析loginToken(就是flutter獲取到的token),是不行滴,這個要注意,我卡這裏很久了QAQ

用nodejs換取手機號密鑰

根據點擊一鍵登錄獲取到的token,使用CURL執行,會返回9210(提示參數錯誤),能夠用語言代碼解析,我放個nodejs換取手機號密文成功的代碼

var request = require('request');

var headers = {
    'Content-Type': 'application/json'
};

var loginToken = "tg9Z2evKEO/rD7naE1JnCYTbMLirZZgn45FrbAynCA0aukCbC8dzjuWAHI+d9ZjB4vs1ac25U8cJxkGbsBZGXssXpn7aR0vQ0M977qIbkDz/e9DsD+ueQFt/iWHV+ZR4YoDYf9+lMrePqLzTyOx4RiDakHQrLUlUC6G7kznJCSI="
var params = {
    loginToken: loginToken,
    exID:""
}
var dataString = JSON.stringify(params)

var options = {
    url: 'https://api.verification.jpush.cn/v1/web/loginTokenVerify',
    method: 'POST',
    headers: headers,
    body: dataString,
    auth: {
        'user': '這個是應用的key',
        'pass': '這個是應用服務端的密碼'
    }
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

request(options, callback);

複製代碼

手機號密文解密

JAVA 解密

import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

public class RSADecrypt {
    public static void main(String[] args) throws Exception {
        String encrypted = "iZT省略20字veq0=";
        String prikey = "MII省略20字Kqw==";
        String publicKey = "省略20字";
        
        System.out.println("解密 result 111");
        String result = decrypt(encrypted, prikey);
        System.out.println(result);
    }

    public static String decrypt(String cryptograph, String prikey) throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(prikey));
        PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);

        Cipher cipher=Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        byte [] b = Base64.getDecoder().decode(cryptograph);
        return new String(cipher.doFinal(b));
    }
}
複製代碼

親測能夠,若是報錯,應該是密文問題。
若有須要能夠下方評論找我要加密的方法,pkcs8 java加解密由皮皮鼠(oops)提供。
(若是用本身的解密方法,報錯,若是方法沒有問題,那麼就是少了一個步驟,解密傳入的密文須要base64解碼,代碼: Base64.getDecoder().decode)

有一個很重要的一點,pkcs8適合java,其餘語言能夠用工具把pkcs8轉pkcs1,支付寶開放平臺有一個轉換的地方

python安裝pycryptodome報錯了。

php

<?php
   $prefix = '-----BEGIN RSA PRIVATE KEY-----';
   $suffix = '-----END RSA PRIVATE KEY-----';
   $result = '';

   $encrypted = null;
   $prikey = null;

   $key = $prefix . "\n" . $prikey . "\n" . $suffix;
   $r = openssl_private_decrypt(base64_decode($encrypted), $result, openssl_pkey_get_private($key));

   echo $result . "\n";
複製代碼

nodejs

const crypto = require('crypto')

var privateStr = `MIIXXXXXXXXXXXXXXKqw==`
var publicStr = `MxxxxXXXXXXXXXXXXXxxxQAB`
var 公鑰pem = `-----BEGIN PUBLIC KEY-----\n${publicStr.replace(/(.{64})/g, '$1\n')}\n-----END PUBLIC KEY-----`.toString('ascii')
var 私鑰pem = `-----BEGIN PRIVATE KEY-----\n${privateStr}\n-----END PRIVATE KEY-----`
var 一鍵登錄密文 = "";

//私鑰解密
const decodeData = crypto.privateDecrypt({key: 私鑰pem, padding: crypto.constants.RSA_PKCS1_PADDING}, Buffer.from(一鍵登錄密文, 'base64'));
console.log("手機號: ", decodeData.toString())
複製代碼

這裏有一個須要注意的地方

Buffer.from(密文, 'base64') 不等於 new Buffer(
    new Buffer(密文.toString('base64'), 'base64').toString(),
    'utf-8'
)
複製代碼

(若是密鑰公鑰沒有換行的話,請直接用上面的代碼,若是已經下載就是pem文件,那麼直接替換[私鑰/公鑰]pem)

nodejs這一塊我摸索了很久,若是有幫助,請點個贊,謝謝~~

相關連接

github.com/jpush/jveri…
docs.jiguang.cn/jverificati…
github.com/jpush/jveri…
github.com/BaseflowIT/…

相關文章
相關標籤/搜索