zoukankan      html  css  js  c++  java
  • 企业项目开发--cookie(3)

    此文已由作者赵计刚授权网易云社区发布。

    欢迎访问网易云社区,了解更多网易技术产品运营经验。


    2.2.3、AdminController

      1 package com.xxx.web.admin;
      2 
      3 import java.util.List;
      4 
      5 import javax.servlet.http.HttpServletRequest;
      6 import javax.servlet.http.HttpServletResponse;
      7 
      8 import org.springframework.beans.factory.annotation.Autowired;
      9 import org.springframework.stereotype.Controller;
     10 import org.springframework.web.bind.annotation.RequestMapping;
     11 import org.springframework.web.bind.annotation.RequestParam;
     12 import org.springframework.web.bind.annotation.ResponseBody;
     13 import org.springframework.web.servlet.ModelAndView;
     14 
     15 import com.xxx.model.userManagement.Admin;
     16 import com.xxx.service.userManagement.AdminService;
     17 import com.xxx.util.admin.AdminCookieUtil;
     18 
     19 /**
     20  * adminController
     21  */
     22 @Controller
     23 @RequestMapping("/admin")
     24 public class AdminController {
     25     
     26     @Autowired
     27     private AdminService adminService;
     28     
     29     /**
     30      * 管理员注册
     31      */
     32     @ResponseBody
     33     @RequestMapping("/register")
     34     public boolean register(@RequestParam("username") String username,
     35                             @RequestParam("password") String password){
     36         Admin admin = new Admin();
     37         admin.setUsername(username);
     38         admin.setPassword(password);
     39         
     40         boolean isRegisterSuccess = adminService.register(admin);
     41         
     42         return isRegisterSuccess;
     43     }
     44     
     45     /**
     46      * 管理员登录
     47      */
     48     @RequestMapping("/login")
     49     public ModelAndView login(@RequestParam("username") String username,
     50                               @RequestParam("password") String password,
     51                               HttpServletResponse response){
     52         
     53         
     54         Admin admin = adminService.login(username, password);
     55         
     56         ModelAndView modelAndView = new ModelAndView();
     57         if(admin == null){
     58             modelAndView.addObject("message", "用户不存在或者密码错误!请重新输入");
     59             modelAndView.setViewName("error");
     60         }else{
     61             modelAndView.addObject("admin", admin);
     62             modelAndView.setViewName("userinfo");
     63             /*
     64              * 这为什么不直接传一个username,而传了一个admin,
     65              * 是因为在实际开发中,你传过去的信息可能不只是username,还有用户手机号、地址等等
     66              */
     67             AdminCookieUtil.addLoginCookie(admin, response);
     68         }
     69         
     70         return modelAndView;
     71     }
     72     
     73     /*****************************mybatis xml方式解决的问题*******************************/
     74     /**
     75      * 根据username或password查找List<Admin>
     76      */
     77     @ResponseBody
     78     @RequestMapping("/findAdmin")
     79     public List<Admin> findAdmin(@RequestParam(value="username",required=false) String username,
     80                                     @RequestParam(value="password",required=false) String password,
     81                                     @RequestParam("start") int start,
     82                                     @RequestParam("limit") int limit,
     83                                     HttpServletRequest request){
     84         Admin admin = AdminCookieUtil.getLoginCookie(request);
     85         if(admin == null){//未登录
     86             return null;
     87         }
     88         List<Admin> adminList = adminService.findAdmin(username, password, start, limit);
     89         return adminList;
     90     }
     91     
     92     /**
     93      * 插入一个用户并返回主键
     94      * 注意:get请求也会自动装配(即将前台传入的username和password传入admin)
     95      */
     96     @ResponseBody
     97     @RequestMapping("/insert")
     98     public Admin insertAdminWithBackId(Admin admin){
     99         return adminService.insertAdminWithBackId(admin);
    100     }
    101 }

    说明,这个类只修改了两个方法login()和findAdmin()。

    测试:

    • 向浏览器写入cookie


    • 从浏览器读cookie


    注意:

    • 上述我们发了两个cookie,其中username的value没有加密,是因为这个value不是私密数据且我们在前台会直接使用,这样的话,省去了js解密的过程。

    • 对于allinfo的加密是为了在浏览器端不让用户将cookie看的那么明显,保护一些私密数据;或者在整个传输过程中,即使被窃听者获取了,也难以知道其中的cookie值。但是,如果窃听者获取了allinfo这个cookie后,就可以使用这个cookie模拟登录然后做一些操作,这个不知道cookie机制会怎样解决?(答案见最下方)

    • 对于allinfo的加密而言,仅使用AES加密事实上也不太合适,因为如果窃听者窃听到你的cookie后,对其进行篡改,当请求头再将这些信息传递过来的时候,可能经过json转化后就会是另一个Admin的信息了,如果需要防止这种情况发生,需要同时对cookie值进行消息摘要加密了(具体的消息摘要加密可以参照"Java加密与解密"系列博客),当然,在绝大多数情况下,如果窃听者不知道你的cookie值得话,如果他对这个值进行了随意的篡改,那么将来在将这个值进行解密后,对其转化成json的过程中就会抛出异常,因为解密后的json串很可能就不符合json的格式了,所以绝大多数情况下,仅适用于AES是可行的。

    • 对于cookie的name实际上也应该加密,加密后浏览器端或窃听者截到的cookie他就不知道是什么意思了,这个加密非常简单,直接在线下使用SHA256出一个字符串或者就使用上边所讲的AES的生成key的方法生成一个就好,然后写在name中,代码再列一遍:

      String key = Base64.encodeBase64String(AESUtil.getKey());

     

    • cookie不可以在多种浏览器之间共享,因为每个浏览器存cookie路径不是一样的

    • 同一种浏览器,多个标签页共享的话,需要再生成cookie的时候添加cookie的有效期;否则cookie为会话cookie,这种客户端是不会把cookie存到硬盘上的,其他标签也无法获取到cookie

     

    总结:

    • 如果安全措施搞得好+cookie数量不多+cookie的总大小对带宽的占用可以接受,使用cookie(对于安全措施这一块,cookie被劫持的可能性一般不大,如果不是非常敏感的权限,可以使用记住我这些功能,如果对于敏感权限,例如金钱操作,就强制重新登录,类似于shiro)

    • 对于浏览器禁用cookie的事情,基本可以不考虑,绝大多数现代浏览器都不会禁用cookie。

    疑问:

    • 如果被窃听者劫取到你的cookie,即使你对这些cookie做了加密,使其看不到cookie中的信息,但是其也可以通过该cookie模拟登录行为,然后获得一些权限,执行一些操作。(这是个疑问,记住我这个功能就是这样做的,怎样做到安全的呢?)

    解答:方案

    1、使用权限框架shiro

    注意:shiroshiro保存了你的账户名(编码)和可记住密码的有效时间到cookie里,下次会把账户名带过来,可以允许执行一些非敏感操作。根据你后台设定的权限;当然对于敏感权限的话,一定要重新登录才行。(当然,由于还是存在cookie里,可能还是存在会被劫持的情况)

    具体看下边图片:("记住我"的功能)



    2、https(即使被劫取到,也不能重传)

    这个是可以解决上边问题的,但是https没闹懂。

    3、IP变动

    1)客户端登陆的时候,记录客户端IP到数据库

    2)下次登录从request中获取IP并与前一次记录的IP作对比,如果IP没有发生变化,则得直接进入已登录状态了;如果IP发生了变化,则重新登录,登录之后,修改IP

    3)之后的过程如上

    当然,对于以上这种方式,还有一种改进,就是将用户登录的IP放入缓存(当然可以指定缓存时间),这样每次就可以从缓存中查IP了。

    但是这种方式有个问题,就是说同一台电脑换一个网络环境,这时候IP就变了,就得重新登陆了。

    4、数字签名算法

    数字签名的三个作用中的一个就是"认证数据来源",感觉这会是一个思路,但是具体怎么实现还没想好。如果大家有想好的,帮指点一下!

    数字签名算法的具体实现见"Java加密与解密"《第十四章 数字签名算法--RSA》,链接如下:

    http://www.cnblogs.com/java-zhao/p/5091363.html

     

    有关于session的细节与解决方案,以后再说!


    此文已由作者赵计刚授权网易云社区发布。

    欢迎访问网易云社区,了解更多网易技术产品运营经验。


    相关文章:
    【推荐】 网易云基于 Kubernetes 的深度定制化实践
    【推荐】 【工程实践】服务器数据解析
    【推荐】 The Beam Model:Stream & Tables翻译(上)

  • 相关阅读:
    golang删除数组某个元素
    golang用通道实现信号量,控制并发个数
    什么是ScaleIO中的forwards rebuild和backwards rebuild?
    SQL Server中的database checkpoint
    如何将thick provision lazy zeroed的VMDK文件转换为thick provision eager zeroed?
    LoadTestAgentResultsLateException in VS2010
    SQL Server Instance无法启动了, 因为TempDB所在的分区没有了, 怎么办?
    VMware vCenter中, 如何辩认虚机上Raw Device Mapping过了的一块物理磁盘?
    SQL Server AlwaysOn Setup Step-By-Step Guide
    TPC-E在populate测试Database时需要注意的一些事项
  • 原文地址:https://www.cnblogs.com/163yun/p/10143319.html
Copyright © 2011-2022 走看看