美文网首页
go中国家新闻出版署实名认证

go中国家新闻出版署实名认证

作者: 岑吾 | 来源:发表于2021-10-25 15:27 被阅读0次

    随着网络游戏防沉迷系统的接入,实名认证验证也是一个必不可少的部分,网上有第三方的实名认证但基本上都收费,国家新闻出版署提供了免费的接口,不过需要自己去提交申请,获取应用标识 (APPID)应用密钥 (Secret Key)业务权限标识(BizId),并将请求服务器的IP设为白名单后,就可以调用https:// api.wlc.nppa.gov.cn/idcard/authentication/check接口来获取实名认真了。

    这个接口中请求体body使用了AES-128/GCM + BASE64算法加密,签名使用了sha256。直接上完整的代码

    import (
        "bytes"
        "crypto/aes"
        "crypto/cipher"
        "crypto/rand"
        "crypto/sha256"
        "encoding/base64"
        "encoding/hex"
        "encoding/json"
        "fmt"
        "io"
        "io/ioutil"
        "net/http"
        "sort"
        "strconv"
        "time"
    )
    
    // 国家新闻出版署配置信息
    type nppaInfo struct {
        AppId     string // 应用标识
        SecretKey string // 应用密钥
        BizId     string // 业务权限标识
    }
    
    var nppa nppaInfo
    
    // 输入国家新闻出版署配置信息
    func NppaInit(appId, secretKey, bizId string) {
        nppa = nppaInfo{
            AppId:     appId,
            SecretKey: secretKey,
            BizId:     bizId,
        }
    }
    
    // 实名验证
    // ai   - 游戏内部成员标识,固定32位字符,一般使用 md5(用户ID)
    // name - 实名信息中的姓名
    // id   - 实名信息中身份证号码
    // 返回
    //      - result 是否验证成功
    //      - errcode 状态码
    //      - errmsg 状态描述
    func NppaCheck(ai, name, id string) (result bool, errcode int, errmsg string ) {
        client := &http.Client{}
    
        // body 参数
        param := map[string]string{
            "ai":    ai,
            "name":  name,
            "idNum": id,
        }
    
        // AES-128/GCM + BASE64算法加密
        jsonParam, _ := json.Marshal(param)
        cipher, _ := gcmEncrypt(string(jsonParam))
        body, _ := json.Marshal(map[string]string{
            "data": cipher,
        })
    
        // post请求地址
        req, _ := http.NewRequest("POST", "https://api.wlc.nppa.gov.cn/idcard/authentication/check", bytes.NewReader(body))
    
        // header头验证信息
        headers := map[string]string{
            "appId":      nppa.AppId,
            "bizId":      nppa.BizId,
            "timestamps": strconv.FormatInt(time.Now().UnixNano()/1e6, 10),
        }
    
        // 签名
        headers["sign"] = sign(headers, string(body))
        headers["Content-Type"] = "application/json;charset=utf-8"
        for k, v := range headers {
            req.Header.Set(k, v)
        }
    
        // 请求
        resp, err := client.Do(req)
        if err != nil {
            return false, -1, "Http请求错误"
        }
        defer resp.Body.Close()
        if resp.StatusCode != 200 {
            return false, resp.StatusCode, "Http请求返回码错误"
        }
    
        str, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            return false, -2, "Http请求返回数据为空"
        }
    
        var msg map[string]interface{}
        err = json.Unmarshal(str, &msg)
        if err != nil {
            return false, -3, "Http请求返回数据格式错误"
        }
    
        ec, ok := msg["errcode"]
        if !ok {
            return false, -3, "Http请求返回数据格式错误"
        }
    
        errcode = int(ec.(float64))
        if errcode != 0 {
            errmsg, _:= msg["errmsg"]
            return false, errcode, errmsg.(string)
        }
    
        data, ok := msg["data"]
        if !ok {
            return false, -3, "Http请求返回数据格式错误"
        }
    
        r, ok := data.(map[string]interface{})["result"]
        if !ok {
            return false, -3, "Http请求返回数据格式错误"
        }
    
        status, ok := r.(map[string]interface{})["status"]
        if !ok {
            return false, -3, "Http请求返回数据格式错误"
        }
    
        errcode = int(status.(float64))
        if errcode == 0{
            return true, 0, "认证成功"
        } else if errcode == 1 {
            return false, errcode, "认证中"
        }else {
            return false, errcode, "认证失败"
        }
    }
    
    func gcmEncrypt(originalText string) (string, error) {
        // 需要解码
        key, _ := hex.DecodeString(nppa.SecretKey)
        block, err := aes.NewCipher(key)
        if err != nil {
            return "", err
        }
    
        aesGcm, err := cipher.NewGCM(block)
        if err != nil {
            return "", err
        }
    
        // 向量
        nonce := make([]byte, aesGcm.NonceSize())
        if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
            return "", err
        }
    
        cipherText := aesGcm.Seal(nonce, nonce, []byte(originalText), nil)
    
        // encode as base64 string
        encoded := base64.StdEncoding.EncodeToString(cipherText)
        return encoded, nil
    }
    
    func sign(headers map[string]string, body string) string {
        var data string
        var keys []string
        // key排序
        for k := range headers {
            keys = append(keys, k)
        }
        sort.Strings(keys)
    
        // 拼接
        for _, k := range keys {
            data = data + k + headers[k]
        }
        data = nppa.SecretKey + data + body
    
        // 对字符串进行sha256哈希
        h := sha256.New()
        h.Write([]byte(data))
        sum := h.Sum(nil)
        return hex.EncodeToString(sum)
    }
    

    调用

    func main() {
        // 初始化
        NppaInit("test-appId","2836e95fcd10e04b0069bb1ee659955b","test-bizId")
    
        // 使用
        userId := "123456"
        name := "岑吾"
        id := "xxxxxxxxxxxxxxxxxx"
        h := md5.New()
        h.Write([]byte(userId))
        ok,code,msg := NppaCheck(hex.EncodeToString(h.Sum(nil)), name, id)
        fmt.Println(ok,code,msg)
    }
    

    详细返回参数可见网络游戏防沉迷实名认证系统

    相关文章

      网友评论

          本文标题:go中国家新闻出版署实名认证

          本文链接:https://www.haomeiwen.com/subject/ulojaltx.html