登录接入

接口说明

为了保证游戏足够的安全性,我们在Token参数值提供了OTP自主验证。我们强烈建议游戏商必须做这一步动作。

平台账号Token,由SDK提供。
格式:"09608220dcf453a6fd2f10ddcc4182f3.1611134087.48234923",
按.分隔,第一个参数是Token,第二个参数是个计数值,第三个参数是验证码。
使用OTP算法,使用计数值,再加上密钥生成验证码(具体生成方式看下面)。再与第三个参数验证码比对。 一次性密码(OTP)介绍

流程图

游戏商实现部分为 5,6,7,8步骤

Token自主验证(游戏商服务器)

PHP 示例代码

token验证例子:

 // secret由Eskyfun提供
 $secret = '745a950f994b7da417cd438e5619ac7329400460';

 //平台SDK提供token、userid参数
 $token = '03c7c0ace395d80182db07ae2c30f034.1499671547.55935154';
 $userid = '1000001';

 //分割token
 $tokenArray = explode('.',$token);
 if(count($tokenArray) == 3){
     //计数器
     $times = $tokenArray[1];
     //验证码
     $code = $tokenArray[2];
     //使用Token、用户ID、密钥,拼接用户唯一密钥值
     $userSecret = $tokenArray[0].$userid.$secret;
     //获取code
     $otp = new Otp();
     $oneCode = $otp->getCode($userSecret,$times);
     //对比验证
     if($oneCode == $code){
         // 登录成功
     }else{
         // 登录失败
     }
 }else{
     // 登录失败
 }

PHP OTP类

1.通过hash_hmac加密方式,获取加密值。

2.再unpack解包加密值得到解包后的数据,再截取32位。

3.再mod取8位(需要则补位)得到验证码

class Otp
{
    protected $_codeLength = 8;
    protected $_timeSec = 30;
    protected $_digest = 'SHA1';

    public function getCode($secret, $timeSlice = null)
    {
        if ($timeSlice === null) {
            $timeSlice = floor(time() / $this->_timeSec);
        }

        // hash加密
        $hm = hash_hmac($this->_digest, (string)$timeSlice, $secret, true);

        // 解包二进制数据,unpack N格式至少需要4个长度
        $value = unpack('N', $hm);
        $value = $value[1];

        // 截取32位
        $value = $value & 0x7FFFFFFF;

        //位数值 eq:10的8次方
        $modulo = pow(10, $this->_codeLength);

        /** 返回值
         * 如果截取32位的值,不够8位,向左填充0,返回值补充至8位
         * 例如$value = 112345678 , $modulo=100000000,$value % $modulo = 12345678,返回12345678
         * 例如$value = 123456 , $modulo=100000000,$value % $modulo = 123456,补充00,返回00123456
       */
        return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT);
    }
}

PYTHON 示例代码

token验证例子:

#secret由Eskyfun提供
secret = '745a950f994b7da417cd438e5619ac7329400460'

#平台SDK提供token、userId参数
token = '03c7c0ace395d80182db07ae2c30f034.1499671547.55935154'
userId = '1000001'

#分割token
tokenArray = token.split(".")
if len(tokenArray) == 3 :
    #计数器
    times = tokenArray[1]
    #验证码
    code = tokenArray[2]
     #使用密钥和用户ID,拼接用户唯一密钥值
    userSecret = tokenArray[0] + userId + secret
    #获取code
    oneCode = OPT.getCode(userSecret,times)
     #对比验证
    if oneCode == code:
        #成功
        print(1)
    else :
        #失败
        print(0)
else:
    #失败
    print(0)

Python OTP类

1.通过hash_hmac加密方式,获取加密值。

2.再unpack解包加密值得到解包后的数据,再截取32位。

3.再mod取8位(需要则补位)得到验证码

class OPT:
    codeLength = 8
    timeSec = 30
    digest = 'SHA1'

    def getCode(secret,timeSlice = None):
        if timeSlice == None:
            timeSlice = math.floor(time.time() - OPT.timeSec)
        #进行加密
        hm = hmac.new(secret.encode('utf-8'),timeSlice.encode('utf-8'),OPT.digest).digest()
        #进行二进制解包
        packArray = struct.unpack('>L',hm[0:4])
        num = packArray[0]
        #补位
        num = num & 0x7FFFFFFF;
        modulo = pow(10, OPT.codeLength);
        sNum = str(num % modulo)
        sNum = sNum.zfill(OPT.codeLength)
        return sNum

JAVA 示例代码

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;

public class Token {

    public static void main(String[] args) {
        //secret由Eskyfun提供
        String secret = "745a950f994b7da417cd438e5619ac7329400460";

        //平台SDK提供token、userId参数
        String token = "03c7c0ace395d80182db07ae2c30f034.1499671547.55935154";
        String userId = "1000001";
        //分割token
        String[] tokenArray = token.split("\\.");
        System.out.println("token中的code=" + tokenArray[2]);
        // 使用密钥和用户ID,拼接用户唯一密钥值
        String key = tokenArray[0] + userId + secret;
        //计数器
        String time = tokenArray[1];
        // 获取code
        OTP opt = new OTP();
        String oneCode = opt.getCode(key, time);
        if (oneCode.equals(tokenArray[2])){
            System.out.println("成功");
        } else {
            System.out.println("失败");
        }
    }


    public static class OTP{
        public String getCode(String userSecret, String time){
            //获取HmacSHA1
            byte[] bytes;
            try {
                SecretKeySpec secretKeySpec = new SecretKeySpec(userSecret.getBytes(), "HmacSHA1");
                Mac mac = Mac.getInstance("HmacSHA1");
                mac.init(secretKeySpec);
                bytes = mac.doFinal(time.getBytes());
            } catch (Exception e) {
                return "";
            }

            //truncate 解包二进制数据
            ByteBuffer data = ByteBuffer.wrap(bytes);
            int num = data.getInt(0) & 0x7FFFFFFF;
            int otp = num % 100000000;
            StringBuilder result = new StringBuilder(Integer.toString(otp));
            while (result.length() < 8) {
                result.insert(0, "0");
            }
            return result.toString();
        }
    }

}

results matching ""

    No results matching ""