Jetty,Java和OAuth入门
使用Okta的身份管理平臺輕松部署您的應用程序 使用Okta的API在幾分鐘之內即可對任何應用程序中的用戶進行身份驗證,管理和保護。 今天嘗試Okta。
Jetty是一個小型,高度可擴展的基于Java的Web服務器和servlet引擎。 它支持HTTP / 2,WebSockets和許多其他協議。 它為大型和小型網站和框架(例如Google AppEngine)提供支持。 因為它是一個Eclipse項目,所以其開源項目稱為Eclipse Jetty。 它符合標準,是開源的,并且可以商業使用。 當托管Java應用程序時,它是Tomcat的主要替代方法。 就像使用Tomcat一樣,您可以同時使用嵌入式和獨立的Jetty。
默認情況下,Spring Boot使用嵌入式Web服務器創建應用程序,這意味著該服務器是嵌入在應用程序代碼本身中的,因此您不必運行單獨的Web服務器即可發布Java Web應用程序。 但是,只需進行一些配置,您還可以將WAR文件發布到單獨的Jetty或Tomcat Servlet容器(老式的應用程序服務器樣式)。 Spring默認情況下也使用Tomcat,但是您可以輕松地更改它,如您所見。
在本教程中,您將構建一個嵌入了Jetty的簡單Web服務。 之后,您將在Spring Boot和Jetty中構建相同的Web服務。 最后,您將使用方法級安全性(以Okta作為OAuth / OIDC提供者)將JWT(JSON Web令牌)身份驗證和授權添加到Web服務。
安裝項目依賴項
開始之前,您需要先安裝一些東西。
Java 11 :該項目使用Java11。如果沒有Java 11,則可以安裝OpenJDK 。 您也可以使用Homebrew安裝OpenJDK。 SDKMAN是用于安裝和管理Java SDK的另一個不錯的選擇。
HTTPie :這是用于發出HTTP請求的簡單命令行實用程序。 您將使用它來測試REST應用程序。 在其網站上查看安裝說明 。
Okta開發人員帳戶 :您將Okta用作OAuth / OIDC提供程序,以向應用程序添加JWT身份驗證和授權。 如果尚未登錄,請訪問他們的網站并注冊他們的免費開發者帳戶之一。
Gradle :這是可選安裝。 如果您從倉庫中下載了本教程的項目,則可以使用Gradle包裝器運行該項目,而無需安裝Gradle。 。 如果您想從頭開始構建項目,則需要安裝Gradle 。
使用Java和Jetty構建簡單的Web服務
本教程的第一步是使用Java和Gradle構建一個簡單的Web服務。 為此,您將使用Gradle的Gretty插件 。 Gretty使使用Gradle在嵌入式servlet容器上運行Web應用程序變得超級容易,并支持Tomcat和Jetty。
如果您選擇從GitHub存儲庫下載本教程的項目 ,請遵循以下幾個步驟,同時我將介紹如何從頭開始構建項目。
git clone https://github.com/oktadeveloper/okta-spring-boot-jetty-example.git首先,打開一個shell并導航到您想要項目駐留的適當目錄(或創建一個目錄)。 使用Gradle CLI初始化項目。
mkdir jetty cd jetty gradle init --type=basic --dsl=groovy --project-name=JettyEmbedded編輯項目根目錄中的build.gradle文件:
plugins { id 'java' id 'war' id 'org.gretty' version '2.3.1' } repositories { jcenter() } dependencies { providedCompile 'javax.servlet:javax.servlet-api:3.1.0' } gretty { contextPath = '/' }我想在這里指出一些事情。 注意plugins塊中的org.gretty插件。 此外,注意javax.servlet:javax.servlet-api您添加依賴使用providedCompile 。 這會將其添加到編譯類路徑中,但不會將其添加到打包的war文件中,因為這將由servlet容器在部署時提供。 最后,請注意,嵌入式servlet容器的上下文路徑已設置為gretty塊中的gretty 。
現在,為Java文件創建根目錄( src/main/java是標準Java根文件夾,加上com.okta.jettyembedded包):
mkdir -p src/main/java/com/okta/jettyembedded創建一個簡單的servlet:
src/main/java/com/okta/jettyembedded/Hello.javapackage com.okta.jettyembedded; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(name = "HelloServlet", urlPatterns = {"hello"}, loadOnStartup = 1) public class Hello extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().print("Howdy"); } }現在您可以運行該應用程序:
gradlew apprun要測試它,請打開另一個shell窗口并使用HTTPie:
http :8080/helloHTTP/1.1 200 OK Content-Length: 5 Date: Fri, 06 Sep 2019 20:23:40 GMT Server: Jetty(9.2.26.v20180806)Howdy您已經構建了一個超級簡單的Web servlet。 它還沒有做很多,但是(希望)可以工作。 注意Hello.java類中的@WebServlet批注。 在這里,您可以配置一些servlet參數,而不是在web.xml文件中。 將此配置移動到代碼中,可以更輕松地構建和維護某些Servlet配置。
接下來,您將看到功能更全的Web Servlet。
通過添加和刪除改進Java Servlet
現在,您將創建一個Web應用程序以跟蹤遠足列表。 它將演示如何支持POST和DELETE操作以及簡單的GET和一些簡單的錯誤處理。
創建一個新的Java文件:
src/main/java/com/okta/jettyembedded/HikesTodoServlet.javapackage com.okta.jettyembedded; import java.io.IOException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.Arrays; import java.util.List;@WebServlet(name = "HikesTodoServlet", urlPatterns = {"hikes"}, loadOnStartup = 1) public class HikesTodoServlet extends HttpServlet { // Not synchronized private List<String> hikes = new ArrayList<>(Arrays.asList("Wonderland Trail", "South Maroon Peak", "Tour du Mont Blanc","Teton Crest Trail", "Everest Base Camp via Cho La Pass", "Kesugi Ridge"));protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { response.getWriter().print(String.join("\n", this.hikes)); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { String hike = request.getParameter("hike"); if (hike == null) { response.setStatus(400); response.getWriter().print("Param 'hike' cannot be null."); } else if (this.hikes.contains(hike)) { response.setStatus(400); response.getWriter().print("The hike '"+hike+"' already exists."); } else { this.hikes.add(hike); response.getWriter().print(String.join("\n", this.hikes)); } } protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws IOException { String hike = request.getParameter("hike"); if (hike == null) { response.setStatus(400); response.getWriter().print("Param 'hike' cannot be null."); } else { this.hikes.remove(hike); response.getWriter().print(String.join("\n", this.hikes)); } } }使用Control-C停止服務器,然后使用gradle apprun重啟服務器。
獲取遠足清單:
http :8080/hikesHTTP/1.1 200 OK ...Wonderland Trail South Maroon Peak Tour du Mont Blanc Teton Crest Trail Everest Base Camp via Cho La Pass Kesugi Ridge發布新的加息:
http -f POST :8080/hikes hike="Pear Lake"HTTP/1.1 200 OK ...Wonderland Trail South Maroon Peak Tour du Mont Blanc Teton Crest Trail Everest Base Camp via Cho La Pass Kesugi Ridge Pear Lake刪除遠足:
http DELETE :8080/hikes hike=="South Maroon Peak"HTTP/1.1 200 OK ...Wonderland Trail Tour du Mont Blanc Teton Crest Trail Everest Base Camp via Cho La Pass Kesugi Ridge Pear Lake現在,嘗試刪除不存在的加息,或發送一個空值:
http DELETE :8080/hikesHTTP/1.1 400 Bad Request ...Param 'hike' cannot be null.要將其部署到實時服務器,您可以按原樣部署項目,使用gradle apprun通過嵌入式Jetty服務器運行應用程序。 您還可以通過使用gradle war構建war文件并將war文件(位于build/libs )復制到服務器上,從而將其部署到外部Jetty服務器。
注意:這是REST服務的非常幼稚的實現。 它使用內存中的ArrayList作為不同步的數據源(因此將在實際的Web servlet中遇到線程問題)。 對于超出本教程范圍的任何內容,您都需要實現某種數據庫后端。 有關如何執行此操作的幫助,請參閱教程末尾列出的示例博客文章。 通常,您還將添加一個PUT端點,并為每個項目分配一個ID用作索引,以便可以更新數據,但這超出了本教程的范圍。
到目前為止,一切進展順利。 在下一部分中,您將使用Spring Boot重新創建相同的Hikes ToDo應用,并使用Okta作為OAuth / OIDC提供者對應用進行JWT令牌認證。
創建一個OIDC應用程序
現在,讓我們前往Okta進行一些實地考察,并為OAuth / OpenID Connect(OIDC)進行設置。 它們一起是用于實施安全授權和身份驗證的一組開放標準。 在本教程中,Okta將充當身份提供者,而您的Spring Boot應用將成為客戶端。
您應該已經在Okta注冊了免費的開發者帳戶。 瀏覽至https://developer.okta.com上的開發人員儀表板。 如果這是您第一次登錄,則可能需要單擊“ 管理員”按鈕。
要配置JWT身份驗證和授權,您需要創建一個OIDC應用程序。
在頂部菜單中,單擊“ 應用程序”按鈕。 單擊添加應用程序按鈕。
選擇應用程序類型Web 。
單擊下一步 。
為應用命名。 我將其命名為“ Spring Boot Jetty”。
在登錄重定向URI下 ,添加兩個新的URI:
- https://oidcdebugger.com/debug
- http://localhost:8080/login/oauth2/code/okta
在“ 允許的授予類型”下 ,選中“ 隱式(混合)” 。
其余的默認值將起作用。
單擊完成 。
使頁面保持打開狀態或記下Client ID 。 生成令牌時需要一點時間。
注意:您將使用oidcdebugger.com重定向URI和隱式授予類型創建訪問令牌,您可以在命令行中使用HTTPie。 第二個URI是Spring Security在使用OAuth登錄功能時用于Okta的默認重定向URI。
使用Jetty創建一個Spring Boot項目
要創建Spring Boot項目,您將使用Spring Initializr 。 查看其GitHub項目以查看其代碼。 Initializr有一個不錯的Web表單,用于配置和下載Spring Boot入門項目,但是對于該項目,您將使用其REST API。
從外殼執行以下命令,以下載已配置的啟動程序項目的zip文件。
http https://start.spring.io/starter.zip \javaVersion==11 \dependencies==web \language==java \type==gradle-project \name==SpringBootJetty \groupId==com.okta.springbootjetty \artifactId==SpringBootJetty \packageName==com.okta.springbootjetty -o SpringBootJetty.zip解壓縮下載的文件,然后在您選擇的IDE中打開目錄。
首先,修改build.gradle文件,以便項目使用Jetty嵌入式容器,而不是默認的Tomcat。 添加spring-boot-starter-jetty依賴關系,并排除spring-boot-starter-tomcat依賴關系。
更改build.gradle文件以匹配以下內容:
plugins {id 'org.springframework.boot' version '2.2.0.RELEASE'id 'io.spring.dependency-management' version '1.0.8.RELEASE'id 'java' }group = 'com.okta.springbootjetty' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11'repositories {mavenCentral() }dependencies {implementation 'org.springframework.boot:spring-boot-starter-web'implementation 'org.springframework.boot:spring-boot-starter-jetty' testImplementation('org.springframework.boot:spring-boot-starter-test') {exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'} }test {useJUnitPlatform() }configurations { compile.exclude module: "spring-boot-starter-tomcat" }現在添加一個WebController.java文件。
src/main/java/com/okta/springbootjetty/WebController.javapackage com.okta.springbootjetty; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.Arrays; import java.util.List;@Controller public class WebController { private List<String> hikes = new ArrayList<>(Arrays.asList("Wonderland Trail", "South Maroon Peak", "Tour du Mont Blanc","Teton Crest Trail", "Everest Base Camp via Cho La Pass", "Kesugi Ridge"));@GetMapping("/") @ResponseBody public String indexGet() { return String.join("\n", this.hikes); } @PostMapping("/") @ResponseBody public String indexPost(@RequestParam String hike, HttpServletResponse response) { if (hike == null) { response.setStatus(400); return "Param 'hike' cannot be null."; } else if (this.hikes.contains(hike)) { response.setStatus(400); return "The hike '"+hike+"' already exists."; } else { this.hikes.add(hike); return String.join("\n", this.hikes); } } @DeleteMapping("/") @ResponseBody public String indexDelete(@RequestParam String hike, HttpServletResponse response) { if (hike == null) { response.setStatus(400); return "Param 'hike' cannot be null."; } else { this.hikes.remove(hike); return String.join("\n", this.hikes); } } }該控制器重新創建在第一個Jetty Hikes ToDo應用程序中發現的相同功能,但現在使用Spring Boot。 您會注意到Spring簡化了一些語法。 @ResponseBody注釋告訴Spring Boot控制器正在直接返回響應主體(與返回模板名稱相反)。 另外,請注意,代碼使用依賴注入來獲取HttpServletResponse以及請求參數。
運行Spring Boot REST服務(確保您的其他服務已停止,否則您將收到端口沖突錯誤):
gradle bootRun在第二個Shell窗口中,獲取遠足列表(注意,下面沒有/hikes路徑)。
http :8080另外,嘗試添加和刪除新的加息。
發布新的加息:
http -f POST :8080 hike="Pear Lake"刪除遠足:
http DELETE :8080 hike=="South Maroon Peak"部署Spring Boot項目
現在,您有了一個在嵌入式Jetty容器上運行的Spring Boot應用程序。 要將其部署到生產服務器,請使用gradle bootJar構建可執行的jar文件,將該jar文件復制到服務器,然后使用java -jar <your jar file name>.jar運行它。 無需單獨的Web服務器,因為此jar包含嵌入式Jetty Web服務器。
注意:對于在同一服務器上具有多個單獨應用程序的應用程序服務器,如果要進行更老式的部署,則需要構建war文件。 有關如何執行此操作的Spring文檔非常有用。 從本質上講,你需要做兩件事情:1)添加war插件到項目的依賴,以及2)改變碼頭或Tomcat依賴于providedRuntime所以它不是在打包的戰爭包括在內。 然后,您構建一個war文件并將其部署到服務器上的servlet Web應用程序路徑。
將OAuth / OIDC登錄名添加到Spring Boot App
您注冊了Okta并創建了OIDC應用程序。 現在是時候配置Spring Boot應用程序以使用OAuth / OIDC進行身份驗證和授權了。
首先,將您的Issuer URI添加到src/main/resources/application.properties文件。 您需要用實際的Okta URL替換{yourOktaUrl} 。 如果您訪問https://developer.okta.com并導航至API和授權服務器 ,則會看到default授權服務器的Issuer URI。
okta.oauth2.issuer=https://{yourOktaUrl}/oauth2/default在該文件中時,從您先前創建的“ Spring Boot Jetty”應用程序中添加客戶端ID和客戶端密鑰。
okta.oauth2.clientId={clientId} okta.oauth2.clientSecret={clientSecret}接下來,您需要在dependencies {}塊中的build.gradle文件中添加以下依賴。
implementation 'com.okta.spring:okta-spring-boot-starter:1.3.0'其中包括Okta Spring Boot Starter,這是一個很好的項目,可簡化Spring Boot對Okta身份驗證和授權的使用。 查看項目頁面以獲取更多信息 。
您還需要更新SpringBootJettyApplication類以匹配以下內容:
package com.okta.springbootjetty;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@SpringBootApplication public class SpringBootJettyApplication extends WebSecurityConfigurerAdapter {public static void main(String[] args) {SpringApplication.run(SpringBootJettyApplication.class, args);}@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().permitAll().and().oauth2Login().and().oauth2ResourceServer().jwt();}}保護您的DELETE和POST端點
configure(HttpSecurity http)方法將具有OAuth 2.0登錄名的Spring Boot應用配置為OAuth 2.0資源服務器,并默認允許所有請求。 您將通過@PreAuthorize批注使用方法級別的安全性來保護下面的DELETE和POST端點。
最后,將@PreAuthorize("isAuthenticated")批注添加到WebController類的indexPost()和indexDelete()方法中。
package com.okta.springbootjetty; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @Controller public class WebController { private List<String> hikes = new ArrayList<>(Arrays.asList("Wonderland Trail", "South Maroon Peak", "Tour du Mont Blanc","Teton Crest Trail", "Everest Base Camp via Cho La Pass", "Kesugi Ridge"));@GetMapping("/") @ResponseBody public String indexGet() { return String.join("\n", this.hikes); } @PreAuthorize("isAuthenticated") // <- ***ADDED***@PostMapping("/") @ResponseBody public String indexPost(@RequestParam String hike, HttpServletResponse response) { if (hike == null) { response.setStatus(400); return "Param 'hike' cannot be null."; } else if (this.hikes.contains(hike)) { response.setStatus(400); return "The hike '"+hike+"' already exists."; } else { this.hikes.add(hike); return String.join("\n", this.hikes); } } @PreAuthorize("isAuthenticated") // <- ***ADDED***@DeleteMapping("/") @ResponseBody public String indexDelete(@RequestParam String hike, HttpServletResponse response) { if (hike == null) { response.setStatus(400); return "Param 'hike' cannot be null."; } else { this.hikes.remove(hike); return String.join("\n", this.hikes); } } }您現在有了受保護的Web服務。 您可以發出GET請求,但無法發布或刪除。 重新啟動服務器,并使用以下HTTPie命令對此進行驗證。
http :8080HTTP/1.1 200 OK ...Wonderland Trail South Maroon Peak Tour du Mont Blanc Teton Crest Trail Everest Base Camp via Cho La Pass Kesugi Ridgehttp -f POST :8080 hike="Pear Lake"HTTP/1.1 403 Forbidden ...{"error": "Forbidden","message": "Forbidden","path": "/","status": 403,"timestamp": "2019-09-07T16:13:59.474+0000" }使用OIDC調試器生成JWT
要訪問受保護的端點,您需要生成一個JWT。 為此,您可以使用OIDC調試器 。 您將需要先前創建的OIDC應用程序中的客戶端ID,以及基本Okta URI(與Issuer URI中的基本URI相同)。
打開OIDC調試器 。
將授權URI更新為: https://{yourOktaUri}/oauth2/default/v1/authorize
從OIDC應用程序將客戶端ID更新為客戶端ID。
在“ 狀態”字段中放置一些內容。 就本教程而言,這可以是任何東西。 此值用于幫助防止跨站點偽造請求。
向下滾動并單擊發送請求 。
將令牌復制到剪貼板,并將其存儲在用于發出請求的shell窗口中的shell變量中。
TOKEN=eyJraWQiOiJIb05xb01mNE9jREltWnBGRnBINjZGTkFOM0J...現在嘗試發布新的加息,然后將其刪除。
http -f POST :8080 hike="Pear Lake" "Authorization: Bearer $TOKEN"HTTP/1.1 200 OK ...Wonderland Trail South Maroon Peak Tour du Mont Blanc Teton Crest Trail Everest Base Camp via Cho La Pass Kesugi Ridge Pear Lakehttp DELETE :8080 hike=="South Maroon Peak" "Authorization: Bearer $TOKEN"HTTP/1.1 200 OK ...Wonderland Trail Tour du Mont Blanc Teton Crest Trail Everest Base Camp via Cho La Pass Kesugi Ridge Pear Lake您還配置了此應用程序以使用Spring Security的oauth2Login() 。 這意味著您可以轉到http://localhost:8080/login ,單擊發行者URL,然后也以這種方式登錄。
了解有關Java,Spring Boot和Spring Security的更多信息
就是這樣。 在本教程中,您了解了如何制作一個簡單的Java servlet服務并使用Jetty運行它。 您還了解了如何在Spring Boot中重新創建相同的服務,如何將其配置為使用Jetty,以及簡化Java代碼。 最后,您了解了如何使用Okta提供的免費開發者帳戶向您的Spring Boot應用程序添加OAuth / OIDC安全性。
您可以在oktadeveloper / okta-spring-boot-jetty-example上的GitHub上找到本教程的代碼。
以下是一些相關的博客文章:
- Java應用程序的簡單令牌認證
- 在15分鐘內使用Spring Boot和Spring Security構建一個Web應用程序
- 創建一個安全的Spring REST API
- 使用Spring Boot和Vue.js構建一個簡單的CRUD應用
如果您對此帖子有任何疑問,請在下面添加評論。 有關更多精彩內容, 請在Twitter上關注@oktadev , 在Facebook上關注我們,或訂閱我們的YouTube頻道 。
使用Okta的身份管理平臺輕松部署您的應用程序 使用Okta的API在幾分鐘之內即可對任何應用程序中的用戶進行身份驗證,管理和保護。 今天嘗試Okta。
翻譯自: https://www.javacodegeeks.com/2019/12/get-started-with-jetty-java-and-oauth.html
總結
以上是生活随笔為你收集整理的Jetty,Java和OAuth入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gmail邮箱国内如何使用gmail邮箱
- 下一篇: Java和Round-Robin上的At