1. 程式人生 > >企業專案開發--cookie(3)

企業專案開發--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翻譯(上)