Spring Security極簡入門三部曲(上篇)

白澤來了發表於2021-05-05

Spring Security極簡入門三部曲(上篇)

大家好,這裡是白澤。最近學校裡一個Spring Boot專案要用到Spring Security做安全相關的工作,好,沒用過,那我先學一下吧。查閱了不少文章,上來就是一堆介面,實現類,過濾器鏈,超級高水平,我看不懂。摸索了兩天終於有點感覺了,就寫一篇兩天前的我希望看到的部落格吧

這篇部落格能讓你初步理解Spring Security框架執行的過程,並用於你的Spring Boot專案中,但如果需要精進這個框架,還需要你閱讀更多原始碼等後續的學習

寫在前面

  • 程式碼在我的github中github專案地址,本篇部落格對應名為spring-security-demo1的專案檔案

  • 學這個框架,不管你是跟著別人的部落格學,還是看視訊學,不跟著寫個小的demo,想學明白需要點天賦

  • 你需要會用Spring Boot,以及一些基本的前端知識(html/css/js),包括thymeleaf模板框架的基礎知識

  • MySQL資料庫相關知識,以及Spring Boot整合Mybatis框架的使用

為什麼要用Spring Security

你也知道Spring Security有兩個功能,認證和授權,認證指的是驗證使用者名稱密碼是否正確(登陸),但你學習這個框架的初衷是想做授權,比如想控制你專案中有些資源(頁面)只有管理員能訪問,有些資源則普通使用者和管理員都能訪問。又或者針對同一個資源,使用者只有檢視的許可權,但是管理員有增、刪、改、查的許可權。

儘管我很想一下子就告訴你這個框架的用法,讓你馬上cv到自己的專案裡,但結合我的學習經歷,我認為,如果你剛開始接觸許可權相關的知識,那麼你很可能需要先梳理一下你自己專案的資料庫設計思路(因為使用者、角色、許可權最終都是存在資料庫裡的),所以別急,先往下看。

資料庫設計

為了實現不同角色訪問許可權的控制,這裡要用到至少5個表

使用者表角色表多對多的關係,用來表示每個使用者分別的是什麼角色(如:A是使用者,B是管理員),二者的關係存放在使用者角色關係表

角色表許可權表也是多對多的關係,用來表示每個角色有什麼許可權(如:對某資源,使用者有檢視許可權,管理員有增加、刪除、修改、檢視許可權),二者關係存放在角色許可權關係表

注意:在通篇部落格中,如果我提到 ” 管理員有訪問XX資源(主要指頁面)的許可權 “,這裡的許可權指的是訪問這個資源的資格(它只限制了角色);而如果我提到 ” 管理員對XX資源有增、刪、改、查的許可權,而普通使用者只有檢視許可權 “,(它不僅限制了角色還細分了不同角色對同一個資源的操作許可權)。而許可權表中存放的是記錄是針對後者這種情況的(因此permission_code也可以理解為以某種操作處理某種資源的後端url是多少

為了幫助理解,我擬了一張permission表(針對學生資源,有增、刪、改、查四個許可權,所以在permission表中有四條記錄)

demo時刻

ps:spring-security-demo1將圍繞使用者表<->角色表展開(且將先不使用資料庫),資料庫的使用,以及角色表<->許可權表部分將在後續部落格講解

實現功能:

  1. 網站分為首頁、登陸頁、使用者頁、管理員頁、報錯頁
  2. 使用使用者名稱密碼登陸,登陸失敗報錯
  3. 首頁、登陸頁所有角色都能訪問
  4. 使用者頁需要USER或ADMIN許可權,管理員頁需要ADMIN許可權(許可權不足時跳轉至403頁面)
  5. 如果使用者沒有登入,則訪問需要許可權的頁面時自動跳轉登入頁面,登陸成功後自動跳轉至訪問的頁面
  6. 別愣著了,快把專案克隆到本地並嘗試執行呀!最好再自己新建一個專案跟著寫一遍~

測試結果:

  1. github專案地址,點選主頁跳轉至登陸頁面,輸入定義好的使用者名稱和密碼
  2. 如果使用者名稱或密碼出錯則在登陸頁顯示錯誤
  3. 如果登陸成功則跳轉至/user(無論是用admin還是user登陸都是預設跳轉至/user)
  4. 如果在登陸狀態下使用者為user,此時點選管理員頁的連線會跳轉至403(許可權不足),而點選使用者頁則可以正常訪問
  5. 如果登陸狀態下使用者為admin,此時點選管理員頁和使用者頁都可以正常訪問
  6. 點選退出登陸則清除登陸賬戶session記錄,跳轉至/login登陸頁
  7. 如果一開始在未登入時點選使用者頁或管理員頁,則會先跳轉至登陸頁提示登陸,輸入資訊後會自動跳回之前請求的使用者頁或者管理員頁,但是,如果起初點選的是管理員頁,而在提示輸入登陸資訊時輸入了user的登陸資訊,則在最終訪問管理員頁面時會出現403提示(因為user賬戶沒有admin許可權)

核心程式碼講解

事實上,需要你編寫的Spring Security相關程式碼其實只涉及到一個類中的不到二十行程式碼~,如果你只想知道怎麼用,完全可以只看那個SecurityConfiguration配置類的程式碼

這個自定義的配置類繼承了Spring Security提供的一個父類WebSecurityConfigurerAdapter,並重寫了它的兩個configure方法,第一個方法在程式執行時於記憶體中建立兩個使用者(使用者名稱&密碼)並賦予角色,我們前端的登陸就是去匹配這兩個定義好的使用者

user使用者,密碼為123(加密處理),賦予USER許可權(角色)

admin使用者,密碼為123(加密處理),賦予USER和ADMIN許可權(角色)

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    /**
     * 在記憶體中建立一個名為 "user" 的使用者,密碼為 "123",擁有 "USER" 許可權,密碼使用BCryptPasswordEncoder加密
     */
    auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
            .withUser("user").password(new BCryptPasswordEncoder().encode("123")).roles("USER");
    /**
     * 在記憶體中建立一個名為 "admin" 的使用者,密碼為 "123",擁有 "USER" 和"ADMIN"許可權
     */
    auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
            .withUser("admin").password(new BCryptPasswordEncoder().encode("123")).roles("USER","ADMIN");
}

第二個重寫的方法定義了訪問/user/路徑下的所有資源需要USER許可權(角色),訪問/admin/路徑下的所有資源需要ADMIN許可權(角色)

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .antMatchers("/","/index").permitAll()
            .antMatchers("/user/**").hasRole("USER")
            .antMatchers("/admin/**").hasRole("ADMIN")
            .and()
            .formLogin()
            .loginPage("/login")    //使用者未登入時,訪問任何需要許可權的資源都轉跳到該路徑,即登入頁面,此時登陸成功後會繼續跳轉到第一次訪問的資源頁面(相當於被過濾了一下)
            .defaultSuccessUrl("/user") //登入認證成功後預設轉跳的路徑,意思時admin登入後也跳轉到/user
            .and()
            .logout()
            .logoutUrl("/logout")   //退出登陸的路徑,指定spring security攔截的登出url,退出功能是security提供的
            .logoutSuccessUrl("/login");//使用者退出後要被重定向的url
}

小結

  1. 在本demo中,我們未用到資料庫去存放使用者和角色的資訊,這在極簡入門中篇中將會講解
  2. 此外我們也沒有在程式碼中模擬對於某項資源不同角色有不同的操作許可權,這在極簡入門的下篇將會講解
  3. 到此為止,你是否對使用者登陸成功後,session中使用者資訊的存放感到好奇?過濾器鏈的作用詳情又是是怎麼樣的?我們後面再做探討
  4. 歡迎評論區留言

相關文章