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