記錄一下在SpringBoot中實現簡單的登錄認證
代碼參考博客:
https://blog.csdn.net/weixin_37891479/article/details/79527641
在做學校的課設的時候,發現了安全的問題,就不懷好意的用戶有可能跳過登錄直接訪問系統的界面和使用裏面的功能,於是想為系統加個安全驗證。現在常用的安全框架我知道的就是Shiro還有SpringSecurity,但這次我不打算用框架,采用攔截器filter和session技術實現了一個基於session的登錄認證。
先簡單地說一下原理:
session和cookie介紹:
首先要知道,session是什麽。 我們知道HTTP是個無狀態的協議,在WEB開發中,服務器可以為每個用戶瀏覽器創建一個會話對象(session對象),註意:一個瀏覽器獨占一個session對象(默認情況下)。因此,在需要保存用戶數據時,服務器程序可以把用戶數據寫到用戶瀏覽器獨占的session中,當用戶使用瀏覽器訪問其它程序時,其它程序可以從用戶的session中取出該用戶的數據,為用戶服務。
而cookie,就是把用戶的數據寫在瀏覽器,session是放在服務器的內存中的。 session和cookie都是為了跟蹤與用戶的會話而誕生的技術
然後cookie和session的簡單區別:
- Cookie是把用戶的數據寫給用戶的瀏覽器。
- Session技術把用戶的數據寫到用戶獨占的session中。
- Session對象由服務器創建,開發人員可以調用request對象的getSession方法得到session對象。
session的實現原理:
- 服務器是如何實現一個session為一個用戶的瀏覽器服務的呢???(千萬要搞清楚,服務器是對每個用戶的瀏覽器都創建一個session對象,也就是說每個瀏覽器用戶都有一塊內存來存他們的信息!!!)
- 在一個用戶向服務器發出請求後,服務器會看這個瀏覽器所夾帶的cookie有沒有sessionId這一項,如果沒有,則說明這個用戶是第一次訪問這個服務器,然後服務器為這個瀏覽器用戶創建一個session和一個獨一無二的sessionid,並把這個id以cookie的形式寫回給客戶機。
- 後面客戶端訪問服務器,都會帶著這個sessionid去,服務器發現客戶機瀏覽器帶session id過來了,就會使用內存中與之對應的session為之服務。
- 額如果瀏覽器也就是客戶端禁止使用cookie怎麽辦,有兩個技術:url重寫 和 隱藏表單域 其實思路都是 想辦法把這個sessionid傳給服務器,讓服務器找到正確的session和這個瀏覽器客戶機對應。
實現思路:
登錄成功的時候,在該瀏覽器用戶所對應的session中,新建一個key為“hasLoginedUsersMap”,值為一個Map<String, Object> hasLoginedUsersMap的鍵值對,顧名思義,就是一個記錄了該客戶端所登陸過的用戶信息的Map。(為什麽不直接記錄一個"user",User的鍵值對,因為考慮到一個瀏覽器可能用多個用戶去登錄……)然後這個Map裏面,每一個鍵值對就是("userId",User),也就是鍵為用戶id,然後值為這個User對象。 所以登錄成功後,就先看session裏面有沒有這個Map,若沒有則建立一個並在這個Map裏面添加這個userid和這個user;如果有這個Map就在這個Map中添加這個用戶的userId和User信息。
每個用戶請求過來,先被Filter攔截下來,經過Filter處理後才到SpringMVC的servlet。在Filter中,看這個瀏覽器用戶的session,看有沒hasLoginedUsersMap這個Map,如果有,就說明該用戶登錄過了,可以繼續訪問,如果沒有這個Map,就重定向到別的界面,就不讓他訪問原來的資源。(我的主頁的請求中帶有用戶的userId,如果是主頁請求,就會去Map中看有沒有這個UserId的信息,如果有就登錄過,沒有的話就不讓他訪問。)
下面貼下代碼,登錄和註銷還有filter中的攔截代碼就不上了,主要看看Filter的註冊:
查到在Springboot中一般有兩種註冊這個FIlter的方法:
1.註解註冊法:
在過濾器上添加WebFilter註解
在啟動類添加ServletComponentScan註解:
@WebFilter(filterName = "sessionFilter",urlPatterns = {"/*"}) public class SessionFilter implements Filter {
@SpringBootApplication @ServletComponentScan public class FileUploadApplication { public static void main(String[] args) { SpringApplication.run(FileUploadApplication.class, args); } }
2.javaConfig註冊:
package com.stuPayment.config; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.stuPayment.util.LoginFilter; @Configuration public class FilterConfig { @Bean public FilterRegistrationBean loginSessionFilter() {//這個類應該是Spring給我們拿來初測filter的 FilterRegistrationBean registration = new FilterRegistrationBean();//新建過濾器的註冊類 registration.setFilter(new LoginFilter());//添加我們寫好的filter registration.addUrlPatterns("/*");//設置filter的過濾的url模式 return registration;//返回這個就是Spring會幫你註入的那個對象 } }
這裏提一下:
當有多個過濾器需要按順序執行時怎麽辦?
使用註解的配置方法不能配置順序,但是可以通過過濾器名字的字典順序實現順序過濾(比如AFilter就會在BFilter前執行),顯然這種方法看起來不怎麽正經。
但是我們可以使用第二種配置方法.
通過給註冊類設置order,order越小,執行優先級越高
@Bean public FilterRegistrationBean someFilterRegistration1() { //新建過濾器註冊類 FilterRegistrationBean registration = new FilterRegistrationBean(); // 添加我們寫好的過濾器 registration.setFilter( new SessionFilter()); // 設置過濾器的URL模式 registration.addUrlPatterns("/*"); //設置過濾器順序 registration.setOrder(1); return registration; }
記錄一下在SpringBoot中實現簡單的登錄認證