手游SDK-登录

一、登录

1、登录的基本流程:(以账密登录为例)

1)调用X_SDK的登录方法,进行SDK登录操作。即弹出登录框,等待用户输入账号密码。
2) X_SDK与SDK服务器进行通信,向SDK服务器传递对应信息。即把账号密码等信息传给服务器。
3)SDK服务器向X_SDK返回token,token中包含了玩家的验证信息。1、2、3 这三步可以理解为调用X_SDK的登录方法,然后等待服务器回调token。
4)X_SDK把token等信息传递给游戏。到这一步X_SDK的任务就完成了。
5)游戏把拿到的token信息,传递给游戏服务器。游戏服务器将数据传递给SDK服务器进行验证。
6)SDK服务器将验证结果返回给游戏服务器。
7)游戏服务器根据返回的结果。返回对应的信息和生成唯一的PlayerID给客户端。

2、账密登录具体操作

1)X_SDK与SDK服务器间的通信。

使用HttpPost向服务器提交数据。
示例代码:(这只是个简单的示例,完善的代码请自行修改)

 //采用post方法向服务器提交数据
    public static void postServer(Context mContext, final String url, final List<NameValuePair> params, final postServerListener listener){ 
        class NetworkThread implements Runnable { 
            @Override
            public void run() { 
                //创建HttpPost对象
                HttpPost httpPost = new HttpPost(url);
                HttpResponse httpResponse = null;
                try { 
                    httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); // 设置httpPost请求参数,格式为UTF_8
                    try { 
                        httpResponse = new DefaultHttpClient().execute(httpPost);
                    }catch (SSLException e){ 
                        SSLSocketFactory.getSocketFactory().setHostnameVerifier(new AllowAllHostnameVerifier());
                        httpResponse = new DefaultHttpClient().execute(httpPost);
                    }


                    int resultCode = httpResponse.getStatusLine().getStatusCode();
                    if (resultCode == 200) {  //连接返回成功
                        String result = EntityUtils.toString(httpResponse.getEntity());// 使用getEntity方法活得返回结果
                        JSONObject json = new JSONObject(result);
                        int code = json.getInt("code");
                        String errMsg = json.optString("message", null);
                        if(code==300){ //服务器返回成功
                            listener.Success(json);
                        }else{ 
                            listener.Fail(code+"",errMsg);
                        }
                    }else{ 
                        listener.Fail(resultCode+"","连接失败");
                    }
                } catch (ClientProtocolException e) { 
                    e.printStackTrace();
                    listener.Fail("","ClientProtocolException");
                } catch (IOException e) { 
                    e.printStackTrace();
                    listener.Fail("","IOException");
                } catch (JSONException e) { 
                    e.printStackTrace();
                    listener.Fail("","JSONException");
                }
            }
        }
        new Thread(new NetworkThread()).start();
    }


    public interface postServerListener{ 
        public void Success(JSONObject json);
        public void Fail(String code,String msg);
    }

X_SDK与SDK服务器之间的通讯需要保证请求的参数不被恶意修改。保证请求数据的一致性。

先介绍一下AES(对称加密算法)和RSA(非对称加密算法)。
对称加密算法
客服端和服务器端共同确定一个用来加密和解密的秘钥。然后客服端在请求服务器是通过该秘钥对数据进行加密,服务器端在接收到请求之后使用该秘钥对数据进行解密。
优势在于加密效率高,而缺点是秘钥需要共享给客户端,具有泄露的风险。

非对称加密算法
服务器端生成公钥和私钥,把私钥发送给客户端。客服端在请求服务器时,通过公钥对数据进行加密。服务器端接收到请求之后,使用私钥对加密的数据进行解密。
优势在于不需要共享私钥,避免了私钥泄露的风险,而缺点是加密效率低,数据量大时较为耗时。

再介绍一下MessageDigest数字摘要。
它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生。如果消息在途中改变了,则接收者通过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了。消息摘要后的结果是固定长度,无论你的数据有多大,哪怕是只有一个字节或者是一个G的文件,摘要后的结果都是固定长度。数字摘要常用算法是MD5、SHA、CRC 等,都是哈希Hash算法。

示例代码:

 //使用对称加密算法和MD5数字摘要的sign生成方法 
    public static String md5Decode32(Map<String, String> data, String time) { 
        String key="XXXXXXXXX"; //对称加密算法中的秘钥
        String content = "";//需要保证不被修改的参数
        for (String keyname:data.keySet()) { 
            content=content+keyname+ data.get(keyname);
        }
        content=content+time+ key;//注意:time一定要传进来,不可以在方法中直接生成。不然时间是对不上的
        byte[] hash;
        try { 
            hash = MessageDigest.getInstance("MD5").digest(content.getBytes("UTF-8"));//使用MD5算法进行数字摘要
        } catch (NoSuchAlgorithmException e) { 
            throw new RuntimeException("NoSuchAlgorithmException",e);
        } catch (UnsupportedEncodingException e) { 
            throw new RuntimeException("UnsupportedEncodingException", e);
        }
        StringBuilder hex = new StringBuilder(hash.length * 2);//对生成的16字节数组进行补零操作
        for (byte b : hash) { 
            if ((b & 0xFF) < 0x10){ 
                hex.append("0");
            }
            hex.append(Integer.toHexString(b & 0xFF));
        }
        return hex.toString();//返回sign
    }

还有密码是不要明文传输和明文保存的,所以要对密码进行加密操作。
加密操作可以使用Android中的Cipher(详细或简单使用)。Cipher可以提供加密和解密的功能。生成Cipher对象时可以传入RSA/ECB/PKCS1Padding或者DES/OFB32/PKCS5Padding两种模式。但不管使用哪种模式,都要和后台保持一致。
示例代码:

    //把明文加密
    public static String encrypt(String content, String key) { 
        try { 
            PublicKey pubkey = "XXXXXXX";
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");//生成Cipher对象
            cipher.init(Cipher.ENCRYPT_MODE, pubkey);//操作模式为加密(Cipher.ENCRYPT_MODE),pubkey为公钥
            byte plaintext[] = content.getBytes("UTF-8");
            byte[] output = cipher.doFinal(plaintext);//得到加密后的字节数组
            String s = new String(android.util.Base64.encode(output, android.util.Base64.DEFAULT));
            return s;
        } catch (Exception e) { 
            e.printStackTrace();
            return null;
        }
    }

登录的示例代码:

 private void SignIn(Context mContext,String userName, String psw){ 
        String url = XXXXXX; //账密登录API
        String encryptPsw = Rsa.encrypt(psw, LOGIN_PUBLIC_KEY); //加密密码
        //设置参数
        List<ValuePair> params = new ArrayList<ValuePair>();
        params.add(new BasicValuePair("user_name", userName));
        params.add(new BasicValuePair("encryptPsw", encryptPsw));
        //设置url
        String time = System.currentTimeMillis()+"";
        Map<String, String> MD5_Parameter_Map = new TreeMap<String, String>(); //有序集合,默认是升序
        MD5_Parameter_Map.put("user_name",userName);
        MD5_Parameter_Map.put("encryptPsw",encryptPsw);
        String sign = Rsa.md5Decode32(MD5_Parameter_Map,time) ;

        params.add(new BasicNameValuePair("sign", sign));
        params.add(new BasicNameValuePair("time", time));

        //请求
        postServer(mContext,url,params, new postServerListener() { 
            @Override
            public void Success(JSONObject json) { 
                //成功
            }

            @Override
            public void Fail(String code, String msg) { 
                //失败
            }
        });
    }

登录成功后一般返回token(已登陆用户的识别码)、UserName(用户名)、uid(用户id)等信息。需要把这些信息(并不一定是全部)返回到游戏,让游戏完成登录。
同时也把这些信息保存起来,可以保存到SharedPreferences。

3、自动登录的具体操作

用户登录时不需要每次都弹出账密登录框,在一定时间内自动登录,方便用户登录游戏。
自动登录一般可以使用token登录。在账密登录成功后会返回token给客户端,同时也会把该token和该用户的对应关系缓存在服务器端。客户端在后续的请求接口中就不用每次都传入用户名和密码,只需要传入token即可。服务器会根据token确定客户端的身份。同时token可设置生效时间,token失效之后,客户端重新请求token。
自动登录示例代码:

private void SignInAuto(Context mContext,UserInfo user){ 
        String url = XXXXXX; //自动登录API
        //设置参数
        List<ValuePair> params = new ArrayList<ValuePair>();
        params.add(new BasicValuePair("autoStr", user.autoStr));
        //设置url
        String time = System.currentTimeMillis()+"";
        Map<String, String> MD5_Parameter_Map = new TreeMap<String, String>();
        MD5_Parameter_Map.put("user_name",userName);
        String sign = Rsa.md5Decode32(MD5_Parameter_Map,time) ;
        params.add(new BasicNameValuePair("sign", sign));
        params.add(new BasicNameValuePair("time", time));

        //请求
        postServer(mContext,url,params, new postServerListener() { 
            @Override
            public void Success(JSONObject json) { 
                //成功
            }

            @Override
            public void Fail(String code, String msg) { 
                //失败
            }
        });
    }

4、手机号登录的具体操作

手机号登录需要先向服务端请求验证码。
获取到验证码之后,再使用手机号和验证码向服务器发起注册请求。
手机号登录示例代码:

  //登录框点击“获取验证码”时调用
    private void getSMSCode(Context mContext,String phone,String type){ 
        String url = XXXXXX; //验证码获取API
        //设置参数
        List<ValuePair> params = new ArrayList<ValuePair>();
        params.add(new BasicValuePair("phone", phone));
        params.add(new BasicValuePair("type",type));
        //设置url
        String time = System.currentTimeMillis()+"";
        Map<String, String> MD5_Parameter_Map = new TreeMap<String, String>();
        MD5_Parameter_Map.put("phone",phone);
        MD5_Parameter_Map.put("type",type);
        String sign = Rsa.md5Decode32(MD5_Parameter_Map,time) ;
        params.add(new BasicNameValuePair("sign", sign));
        params.add(new BasicNameValuePair("time", time));

        //请求
        postServer(mContext,url,params, new postServerListener() { 
            @Override
            public void Success(JSONObject json) { 
                int code = json.getInt("code");
                String errMsg = json.optString("message", null);
                switch (code) { 
                    case 0:
                        //获取验证码成功
                        break;
                    default:
                        //获取验证码失败
                        break;
                }
            }
            @Override
            public void Fail(String code, String msg) { 
                //失败
            }
        });
    }
    //登录框点击“确认”时调用
    private void SignInPhone(Context mContext,String phone,String code){ 
        String url = XXXXXX; //手机号登录API
        //设置参数
        List<ValuePair> params = new ArrayList<ValuePair>();
        params.add(new BasicValuePair("phone", phone));
        params.add(new BasicValuePair("code",code));
        //设置url
        String time = System.currentTimeMillis()+"";
        Map<String, String> MD5_Parameter_Map = new TreeMap<String, String>();
        MD5_Parameter_Map.put("phone",phone);
        MD5_Parameter_Map.put("code",code);
        String sign = Rsa.md5Decode32(MD5_Parameter_Map,time) ;
        params.add(new BasicNameValuePair("sign", sign));
        params.add(new BasicNameValuePair("time", time));
        //请求
        postServer(mContext,url,params, new postServerListener() { 
            @Override
            public void Success(JSONObject json) { 
                //成功
            }
            @Override
            public void Fail(String code, String msg) { 
                //失败
            }
        });
    }

二、注册

账号注册和手机号注册 都和登录的步骤相似,只需要更换对应的API即可。
一键注册可以使用手机设备ID作为唯一标识,进行注册。

上一篇: 手游SDK-概述
下一篇: 手游SDK-登录界面

    原文作者:yeliang23
    原文地址: https://blog.csdn.net/qq_18704911/article/details/103768778
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞