用户身份验证

前一阵子,线上的游戏被黑客着实折腾了一把,也给我好好上了一课。

这次反黑让我深刻认识到一个真理:

完全不能相信客户端信息!

但是,又不能完全去除客户端信息,比如通过parameter传递个用户id什么的,要不然怎么确定是那个人的操作呢,呵呵。

其实,我最初的实现是把用户状态放到了session中,但是随着用户量的增加,后台程序被发布到了多台服务器上。

这样拥有状态区分的session用不了了,不得已使用了Memcache,并且通过userId区分把用户信息保存到了MemcacheServer上。

这样只能通过parameter传递用户id,所以就必须对从客户端传递的用户id进行身份验证。

 

下面是两种验证方法

 

1、通过Cookie验证用户

用户登录游戏的时候进行Cookie设置
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
String sessionKey = (String) request.getParameter(Constants.PARAM_XN_SIG_SESSION_KEY);
  
if (sessionKey == null ) {
     Exception e = new Exception( "xn_sig_session_key is null!" );
     throw e;
}
  
PremierContext.setCurrentUserSessionKey(sessionKey);
  
// 把sessionKey保存到Cookie
Cookie cookie = new Cookie(Constants.COOKIE_KEY_CURRENTSESSIONKEY, sessionKey);
cookie.setMaxAge(Constants.SECONDS_OF_DAY);
response.addCookie(cookie);
// 设置Cookie初始化flag为true,为了初始化Cookie的时候不进行Cookie校验
request.setAttribute(Constants.REQUEST_KEY_INITCOOKIE, true );
 
通过Cookie进行当前用户校验
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 从Memcache取得sessionKey
String sessionKey = (String) MemcacheUtil.get(Constants.MEM_KEY_XN_SIG_SESSION_PREFIX + playerId);
  
// 通过Cookie进行当前用户校验
boolean hasCookie = false ;
if (request.getAttribute(Constants.REQUEST_KEY_INITCOOKIE) == null
         || !(Boolean) request.getAttribute(Constants.REQUEST_KEY_INITCOOKIE)) {
     Cookie[] cookies = request.getCookies();
     if (cookies != null && cookies.length != 0 ) {
         for (Cookie cookie : cookies) {
             if (StringUtils.equals(Constants.COOKIE_KEY_CURRENTSESSIONKEY, cookie.getName())) {
                 hasCookie = true ;
                 if (StringUtils.equals(sessionKey, cookie.getValue())) {
                     // 是同一个用户,验证通过
                     break ;
                 } else {
                     Exception e = new Exception( "playerId is not the Login player!" );
                     throw e;
                 }
             }
         }
     }
     // 如果没有Cookie,说明用户没有正常登录
     if (!hasCookie) {
         Exception e = new Exception( "Cookie is not exit!" );
         throw e;
     }
}

 

2、通过MD5进行签名验证

每个链接传递的参数不止包括用户信息还包括后台生成的签名,获得签名后验证是否合法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
             String sigReceived = request.getParameter( "sig" );
  
             String appId = request.getParameter( "appId" );
  
             String userId = request.getParameter( "userId" );
  
             String inviteId = request.getParameter( "inviteId" );
  
             ArrayList<String> sigList = new ArrayList<String>();
             sigList.add( "appId=" + appId);
             sigList.add( "userId=" + userId);
             sigList.add( "inviteId=" + inviteId);
  
             String sigGenerated = CommonUtil.generateSignature(sigList, Constants.SECRET);
  
             // 如果key相等 或者 算出的sig和收到的sig相等,则校验通过
             if (sigGenerated.equals(sigReceived)) {
...
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
  * 生成签名
 
  * @param params
  * @param secret
  * @return
  */
public static String generateSignature(List<String> params, String secret) {
 
     StringBuffer buffer = new StringBuffer();
     // 对 List<String> params 三个参数字段 采取稳定的字典排序, 然后 append
     Collections.sort(params);
     for (String param : params) {
         buffer.append(param);
     }
     // 继续append 应用的 secret
     buffer.append(secret);
     // 生成 buffer 的 MD5 值
     try {
         java.security.MessageDigest md = java.security.MessageDigest.getInstance( "MD5" );
         StringBuffer result = new StringBuffer();
         try {
             for ( byte b : md.digest(buffer.toString().getBytes( "UTF-8" ))) {
                 result.append(Integer.toHexString((b & 0xf0 ) >>> 4 ));
                 result.append(Integer.toHexString(b & 0x0f ));
             }
         } catch (UnsupportedEncodingException e) {
             for ( byte b : md.digest(buffer.toString().getBytes())) {
                 result.append(Integer.toHexString((b & 0xf0 ) >>> 4 ));
                 result.append(Integer.toHexString(b & 0x0f ));
             }
         }
         return result.toString();
     } catch (java.security.NoSuchAlgorithmException ex) {
         logger.error( "MD5 does not appear to be supported" , ex);
         return Constants.REMARK_EMPTY;
     } catch (Exception e) {
         logger.error( "generateSignature error" , e);
         return Constants.REMARK_EMPTY;
     }
}
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值