javascript
在15分钟内使用Spring Boot和Spring Security构建一个Web应用程序
“我喜歡編寫身份驗證和授權代碼。” ?從來沒有Java開發人員。 厭倦了一次又一次地建立相同的登錄屏幕? 嘗試使用Okta API進行托管身份驗證,授權和多因素身份驗證。
開發人員知道保護Web應用程序安全可能會很麻煩。 正確地做是很難的。 最糟糕的是,“正確”是一個移動的目標。 安全協議會更改。 在依賴項中發現漏洞,并發布了補丁程序。 必須生成大量通常很復雜的樣板代碼。 在過去的十年中,軟件即服務的范式已經泛濫成災,盡管我喜歡和下一個開發人員一樣重新發明輪子(因為顯然,我會比他們雇用的yahoo更好地編寫它),但是安全是一個領域在這里,我很樂意將這項工作分擔給專家。 輸入Okta。
在本教程中,您將使用Spring Boot來構建帶有用戶注冊系統和登錄系統的簡單Web應用程序。 它具有以下功能:
- 登錄和注冊頁面
- 密碼重置工作流程
- 根據組成員身份限制訪問
下載Spring Boot Web App示例項目
您首先需要的是免費的Okta帳戶。 如果您還沒有,請前往developer.okta.com并注冊!
下一步是從GitHub下載本教程的示例項目。
git clone https://github.com/oktadeveloper/okta-spring-simple-app-example.git spring-app該項目使用Gradle作為構建工具以及Thymeleaf模板系統。
運行初始Web應用
從GitHub存儲庫下載示例代碼后,使用以下git命令git checkout tags/Start Start標記: git checkout tags/Start 。
目前,該應用程序尚未受到任何保護。 沒有啟用任何授權或身份驗證(即使build.gradle文件中包含必需的依賴build.gradle )。 繼續并運行示例,方法是打開一個終端,然后從項目根目錄運行命令./gradlew bootRun ( bootRun命令是Gradle Spring Boot插件提供的任務,已添加到build.gradle中的build.gradle文件中。部分)。
在您喜歡的瀏覽器中導航到http://localhost:8080 ,您應該看到以下內容:
如果您點擊“受限”按鈕:
為您的Spring Boot + Spring Security Web App添加項目依賴項
項目依賴關系在build.gradle文件中定義(請參見下文)。 這個文件中有很多事情要做,本教程不會嘗試向您解釋Gradle構建系統。 隨時檢查他們的文檔 。 我只想指出幾件事。
首先,請注意,我們包括了okta-spring-boot-starter 。 該項目大大簡化了Okta與Spring Boot應用程序的集成。 如果沒有此啟動程序,完全可以使用Okta和Spring Boot。 實際上,直到引入“組”和“角色”為止,兩者之間的差異很小(主要涉及application.yml更改)。 但是,一旦開始嘗試集成組和角色,Okta Spring Boot Starter會節省大量代碼。 如果您想更深入一點,請看一下Okta Spring Boot Starter GitHub項目 。
其余的依賴關系涉及Spring和Spring Boot。 您會注意到org.springframework.boot依賴項都沒有版本號。 這是因為Spring io.spring.dependency-management Gradle插件完成了一些幕后魔術。 Spring Boot版本由build.gradle文件頂部附近的構建腳本屬性springBootVersion設置。 基于此版本號,Spring依賴性管理插件決定要包括的依賴性版本。
我們還引入了org.springframework.boot Gradle插件,該插件添加了我們將用于運行應用程序的bootRun任務。
- spring-boot-starter-security和spring-boot-starter-web是Spring Boot的核心依賴項。
- 必須使用spring-security-oauth2-autoconfigure才能使用@EnableOAuth2Sso批注,該批注用于將OAuth和Single Sign-On掛接到我們的應用程序中。
- spring-boot-starter-thymeleaf和thymeleaf-extras-springsecurity4引入了Thymeleaf模板系統,并將其與Spring Security集成。
了解您的Spring Boot應用程序
Java Web應用程序只有三個類文件和幾個模板。 顯然,Spring Boot在后臺進行了大量繁重的工作,但是我們的類文件中發生了什么?
應用程序入口點在SpringSimpleApplication類中:
@SpringBootApplication public class SpringSimpleApplication { public static void main(String[] args) { SpringApplication.run(SpringSimpleApplication.class, args); } }這里發生了兩個重要的事情,這些事情使事情發生了變化:1)我們使用@SpringBootApplication批注,以及2)我們的main方法調用SpringApplication.run()方法。 這是整個Spring / Spring Boot系統的入口。
SpringSecurityWebAppConfig類是一種使用Java代碼配置Spring Boot處理Web應用程序安全性的方式。 在這里,我們使用HttpSecurity對象從所有端點中刪除授權。 默認情況下,Spring Boot的行為是相反的:所有端點都需要授權。
@Configuration public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().permitAll(); } }@Configuration注釋告訴Spring我們正在使用該類作為編程配置的源,從而允許我們重寫configure()方法。
最后一個Java類SimpleAppController是我們唯一的控制器對象。 Spring Boot Web應用程序中的控制器是URL請求映射到Java代碼的地方。 @Controller注釋告訴Spring此類是一個控制器。
@Controller class SimpleAppController { @RequestMapping("/") String home() { return "home"; } @RequestMapping("/restricted") String restricted() { return "restricted"; } }使用@RequestMapping批注在類方法和URL之間建立連接。
我們有兩個映射:
請記住,一開始實際上沒有任何“限制”,所以不要為此感到困惑。 您將鎖定該映射一點。
還要注意,這些類返回一個簡單的文本字符串,但這會自動變成完整的html文件。 這是build.gradle文件中包含的Thymeleaf依賴項的一部分。 這些字符串被假定為模板文件名,默認情況下是類路徑上templates目錄中的路徑。
因此,“ home”被映射到src/main/resources/templates/home.html模板文件。 當將Web應用程序打包到最終的jar中時,會將整個資源文件夾復制到類路徑中,以便可以在運行時訪問templates目錄。
為OAuth 2.0單一登錄設置Okta
現在,您將為我們的應用設置授權。 Okta使這個超級容易。 您應該已經注冊了一個免費的developer.okta.com帳戶。 現在,您將創建一個OpenID Connect(OIDC)應用程序,以與OAuth 2.0單一登錄(SSO)一起使用。
如果您還不熟悉它們的話,可能會有很多術語和縮寫。 很簡單, OAuth 2.0是授權的行業標準-一種標準化且經過測試的方法,授權服務器和應用程序可以通過該方法進行通信以促進用戶授權。 OpenID Connect是OAuth 2.0之上的一層,用于標準化和簡化授權過程以及提供用戶驗證。 它們一起為應用程序與提供身份驗證和授權服務的遠程服務器(例如Okta)進行交互提供了一種行之有效的方法。
要創建OIDC應用,請打開Okta開發人員信息中心。 單擊“ 應用程序”頂部菜單項,然后單擊“ 添加應用程序” 。
您應該看到以下屏幕。 單擊“ Web”選項的圖標。 單擊下一步 。
您需要更新一些初始配置選項。 首先將名稱更改為更具描述性的名稱。 我使用了“ Okta Spring Boot簡單Web應用程序”。 接下來,將登錄重定向URI更新為http://localhost:8080/login 。 單擊完成 。
這將帶您進入新應用程序的常規配置選項卡。 向下滾動并記下客戶端ID和客戶端密碼。 稍后您將需要這些。
這就是為Okat設置Okta所需要做的一切! 現在,讓我們返回Spring Boot應用程序,并將新的OIDC應用程序掛接到Spring Boot應用程序中。
為單點登錄(SSO)配置Spring Boot應用
現在,您需要配置Spring Boot應用程序以與Okta服務器進行交互。 這非常容易。 我們需要做兩件事:
首先將@EnableOAuth2Sso批注添加到SpringSecurityWebAppConfig類。
@EnableOAuth2Sso @Configuration public class WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().permitAll(); } }@EnableOAuth2Sso批注會做很多事情。 值得深入了解正在發生的事情。 您可以查看有關注解本身的Spring文檔 ,以及它們的Spring Boot和OAuth2教程 。
我想指出的一件事(公元前這使我煩惱了一陣子,而我只是想出了這一點)是,您可以將此注釋放在項目中的其他類上。 但是,如果這樣做,請注意Spring將創建一個WebSecurityConfigurerAdapter并將其添加到安全鏈中。 由于我們還將創建一個WebSecurityConfigurerAdapter,因此將有兩個,并且您將收到有關鏈訂單沖突的錯誤。 這是因為兩個WebSecurityConfigurerAdapters在默認情況下將使用相同的鏈順序。 您可以通過在自定義類中添加@Order(101)批注來解決此錯誤。 但是,更好的方法是將@EnableOAuth2Sso批注添加到我們的WebSecurityConfigurerAdapter類WebSecurityConfigurerAdapter ,Spring將使用該類而不是創建重復的類。
您需要進行的第二個更改是更新src/main/resources/application.yml文件,為來自Okta OIDC應用程序的OAuth SSO值填寫一些Okta特定的配置選項。
您需要從上面創建的應用程序中填寫您的客戶ID和客戶機密。 您還需要更改發行者URL,以使其反映您的Okta預覽URL,例如dev-123456.oktapreview.com 。
server: port: 8080 spring: resources: static-locations: "classpath:/static/" okta: oauth2: issuer: https://{yourOktaDomain}/oauth2/default clientId: {yourClientId} clientSecret: {yourClientSecret}rolesClaim: groups完善我們的權限
現在,您將要更新SpringSecurityWebAppConfig類,以便擁有一個公共主頁和一個受限制的“受限制”頁面。 我們通過對HttpSecurity對象使用Spring的流暢API來實現此目的。
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@EnableOAuth2Sso @Configuration public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/").permitAll() // allow all at home page.antMatchers("/img/**").permitAll() // allow all to access static images.anyRequest().authenticated(); // authenticate everything else!} }重新啟動您的應用程序,現在您應該能夠:
本教程中的這一點與GitHub存儲庫中的OktaOAuthSSO標簽相對應。
看看Thymeleaf模板
總體而言,Thymeleaf模板是很容易解釋的,但是我確實想指出幾件事。 Thymeleaf模板是完全有效HTML5,這很好。 如果您想深入了解,可以訪問他們的網站和他們的文檔 。
我想指出的是模板如何引入身份驗證信息。 為此,我們使用了thymeleaf-extras-springsecurity插件。 這是包含在build.gradle文件中的以下行:
compile ("org.thymeleaf.extras:thymeleaf-extras-springsecurity4")并且作為主<html>標記上的XML名稱空間屬性包含在模板文件中。
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"這個插件使我們可以檢查是否使用帶有自定義SPEL表達式(Spring表達式語言)的th:if屬性對用戶進行了身份驗證。 它還允許我們插入身份驗證屬性。 在下面,您將看到一個跨度<span th:text="${#authentication.name}"></span> ,該<span th:text="${#authentication.name}"></span>用于插入已驗證用戶的名稱。
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"> <head> <!--/*/ <th:block th:include="fragments/head :: head"/> /*/--> </head> <body> <div class="container-fluid"> <div class="row"> <div class="box col-md-6 col-md-offset-3"> <div class="okta-header"> <img src="img/logo.png"/> </div> <!--/* displayed if account IS NOT null, indicating that the user IS logged in */--> <div th:if="${#authorization.expression('isAuthenticated()')}"> <h1 th:inline="text">Hello, <span th:text="${#authentication.name}"></span>!</h1> <a href="/restricted" class="btn btn-primary">Restricted</a> </div> <!--/* displayed if account IS null, indicating that the user IS NOT logged in */--> <div th:unless="${#authorization.expression('isAuthenticated()')}"> <h1>Who are you?</h1> <a href="/restricted" class="btn btn-primary">Restricted</a> </div> </div> </div> </div> </body> </html>thymeleaf-extras-springsecurity插件還具有其他一些不錯的功能。 如果您想更深入一點,請查看GitHub上的項目存儲庫 。
通過組成員身份安全訪問
本教程的下一步是使用將在Okta上創建和定義的用戶組添加基于組的身份驗證。 一個非常常見的示例是讓網站的“管理”部分和網站的“用戶”部分,以及可能向所有人開放的公共主頁。 在此示例中,“管理員”和“用戶”將對應于兩個不同的組,其中經過身份驗證的用戶可以是其成員。 我們要做的是能夠基于用戶組成員身份限制對URL端點的訪問,并能夠將用戶分配給這些組。
旁注:小組與角色。 有什么不同?
- “組”是用戶的集合,并且權限已分配給該組。 一般來說,至少在整個會話期間,組成員資格是相對靜態的。
- “角色”是用戶在該角色下執行操作時可以繼承的一組權限。 角色本質上通常更具動態性。 用戶可以具有許多角色。 經常根據復雜的標準激活或停用角色,并且在整個用戶會話中經常可能會更改角色。
實際上,對于簡單的授權系統,它們非常相似。 主要區別在于,組基于個人身份進行分類,而角色則基于允許的活動進行分類。 您可能會在狂野的互聯網上看到無視這種差異的應用程序和教程,因為它們在功能上有些微妙。 (但是現在您知道了。您可以進入所涉及的教程的評論主題,并撰寫評論以糾正作者。)
在Okta中配置授權組
轉到您的developer.okta.com儀表板。 從頂部菜單中,轉到“ 用戶” ,然后單擊“ 組” 。
單擊添加組按鈕。
將組命名為“ Admin”并對其進行描述(我放了“ Administrators”,無論您在這里實際輸入什么,都無所謂,只是描述性的)。
單擊組名稱以打開組,然后單擊添加成員按鈕。 將您的用戶添加到Admin組。
接下來,添加一個不是管理員的新用戶。
- 從頂部菜單轉到“ 用戶 ”,然后單擊“ 人員” 。
- 單擊添加人 。
- 填寫彈出表單:
- 名:不
接下來您需要做的是向默認授權服務器添加一個“組”聲明。
- 從頂部菜單轉到API ,然后單擊“ 授權服務器 ”
- 單擊默認授權服務器。
- 單擊“ 索賠”選項卡。
- 點擊添加聲明按鈕。
- 更新彈出表單以匹配下面的圖像
- 名稱:團體
您在這里所做的就是告訴Okta在發送給您的應用程序的訪問令牌中包含“組”聲明。 這是Okta的OAuth方法,用于向您的應用程序告知您已通過身份驗證的用戶所屬的組。 令人困惑的是,這些在Spring應用程序端被稱為“權威”,這是OAuth服務器與應用程序通信的組/角色/特權的抽象術語。
現在我們有兩個用戶。 您的主要用戶(已添加到Admin組中)和一個新用戶(不在admin組中)。 我們還配置了Okta,將群組聲明添加到訪問令牌中。 現在,我們要做的就是對應用程序代碼進行一些更改!
更新您的Spring Boot + Spring Security App以使用基于組的授權
Okta Spring Boot Starter真正開始發揮作用。 通常,如果您想將我們發送令牌的安全組和組聲明映射到應用程序中的組,則必須編寫一兩個提取程序類來處理提取操作,也許還要編寫一個組類。 Okta Spring Boot Starter可以為您完成所有這些工作!
您要做的第一件事是在SpringSecurityWebAppConfig類中添加以下注釋。
@EnableGlobalMethodSecurity(prePostEnabled = true)像這樣:
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;@EnableOAuth2Sso @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter { /* class contents omitted for brevity */ }此注釋啟用了我們將要使用的下一個注釋@PreAuthorize注釋。 該注釋使我們可以使用Spring Expression Language(SpEL)謂詞來確定控制器方法是否得到授權。 謂詞表達式會在應用程序甚至進入控制器方法之前執行(因此需要“預先”授權)。
在SimpleAppController類中,添加一個名為admin的新方法,如下所示:
import org.springframework.security.access.prepost.PreAuthorize;@Controller class SimpleAppController { /* other controllers omitted for clarity */ @RequestMapping("/admin") @PreAuthorize("hasAuthority('Admin')") String admin() { return "admin"; } }概括一下,此方法執行以下操作:
- 為/admin url端點創建一個映射;
- 為/admin端點分配基于SpEL的授權方案;
- 并簡單地返回Thymeleaf模板的名稱,假設該/templates位于/templates目錄中(我們將在下一個目錄中創建)。
創建新的管理模板頁面。 在src/main/resources/templates目錄中,創建一個名為admin.html的新文件,其內容如下:
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"> <head> <!--/*/ <th:block th:include="fragments/head :: head"/> /*/--> </head> <body> <div class="container-fluid"> <div class="row"> <div class="box col-md-6 col-md-offset-3"> <div class="okta-header"> <img src="img/logo.png"/> </div> <h1>Welcome to the admin page!</h1> <a href="/" class="btn btn-primary">Go Home</a> </div> </div> </div> </body> </html>您可能會問自己@PreAuthorize批注中使用的SpEL表達式是什么意思。 為什么SpEL表達式具有hasAuthority而不具有hasGroup ? 正確的答案有些復雜,這與Spring在不同上下文中調用權限特權和權限有關,可以在應用程序中將其映射到組和角色。 當使用Spring Boot和OAuth時,“權限”通常等同于“角色”,這很好。 但是您說我們使用的是群組,而不是角色? 對。 實際上,在這種情況下,這沒關系,因為Okta知道我們在談論群組,而應用程序知道我們在談論群組,并且在中間,我們僅使用group聲明和Authority字段來傳達文本代表用戶所屬組的字符串。
有用的提示:
如果要檢查Spring Boot App正在接收的身份驗證信息,可以在return語句之前的控制器方法之一中添加以下行。
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();確實在此行上或其后設置一個斷點,然后使用允許您檢查身份驗證對象的調試器運行該應用程序。 這是學習和調試問題的好方法。
試用您的新Spring Boot + Spring Security Web App!
就是這樣。 您應該能夠重新啟動應用程序并以兩個不同的用戶身份登錄。 只有添加到“管理員”組的用戶才能訪問“管理員”頁面。 您必須直接導航到http:// localhost:8080 / admin(因為我們沒有添加鏈接或按鈕)。 如果您嘗試與其他用戶一起導航到管理頁面,則會看到漂亮的whitelabel錯誤頁面,其中顯示403 /未經授權的錯誤。
請記住,在用戶之間切換時,您必須停止應用程序,注銷您的developer.okta.com帳戶,然后重新啟動應用程序。 您也可以在瀏覽器中使用隱身窗口。
本教程的這一部分與GroupsAuth標記相對應,您可以使用以下命令git checkout tags/GroupsAuth 。
了解有關Spring Boot,Spring Security和安全用戶管理的更多信息
您在這里取得了一些實際進展。 您了解了如何創建一個簡單的Spring Boot應用程序以及如何使用Thymeleaf模板。 您已經了解到Okta使OAuth 2.0 Single Sign-On集成到您的應用中有多么容易。 您已經了解了如何使用WebSecurityConfigurerAdapter子類和http.authorizeRequests() API來限制對控制器端點的訪問。
最后,您已經了解了如何在Okta上創建組和用戶,如何將它們綁定到Spring Boot應用程序中,以及如何使用@PreAuthorize批注根據組成員身份配置授權。
如果您想查看這個完整的項目,可以在Github上找到該倉庫: https : //github.com/moksamedia/okta-spring-simple-app 。
如果您想了解有關Spring Boot,Spring Security或Okta的更多信息,請查看以下任何出色的教程:
- Spring Boot,OAuth 2.0和Okta入門
- 15分鐘內將單一登錄添加到您的Spring Boot Web App
- 使用多重身份驗證保護您的Spring Boot應用程序安全
- 使用Spring Boot和GraphQL構建安全的API
如果您想深入研究,請查看Okta Spring Boot Starter GitHub頁面 。
如果您對此帖子有任何疑問,請在下面添加評論。 有關更多精彩內容, 請在Twitter上關注@oktadev , 在Facebook上關注我們,或訂閱我們的YouTube頻道 。
“我喜歡編寫身份驗證和授權代碼。” ?從來沒有Java開發人員。 厭倦了一次又一次地建立相同的登錄屏幕? 嘗試使用Okta API進行托管身份驗證,授權和多因素身份驗證。
“使用Spring Boot和Spring Security在15分鐘內構建Web應用程序”最初于2018年9月26日在Okta開發人員博客上發布。
翻譯自: https://www.javacodegeeks.com/2019/02/build-web-app-spring-boot-spring-security.html
總結
以上是生活随笔為你收集整理的在15分钟内使用Spring Boot和Spring Security构建一个Web应用程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: activemq 实例_在一台计算机上运
- 下一篇: 西方经济学的研究对象是什么 西方经济学的