
- Spring Boot 教程
- Spring Boot - 首頁
- Spring Boot - 簡介
- Spring Boot - 快速入門
- Spring Boot - 啟動
- Spring Tool Suite
- Spring Boot - Tomcat 部署
- Spring Boot - 構建系統
- Spring Boot - 程式碼結構
- Spring Bean & 依賴注入
- Spring Boot - 執行器
- Spring Boot - 啟動器
- Spring Boot - 應用屬性
- Spring Boot - 配置
- Spring Boot - 註解
- Spring Boot - 日誌
- 構建RESTful Web 服務
- Spring Boot - 異常處理
- Spring Boot - 攔截器
- Spring Boot - Servlet 過濾器
- Spring Boot - Tomcat 埠號
- Spring Boot - Rest 模板
- Spring Boot - 檔案處理
- Spring Boot - 服務元件
- Spring Boot - Thymeleaf
- 使用RESTful Web 服務
- Spring Boot - CORS 支援
- Spring Boot - 國際化
- Spring Boot - 定時任務
- Spring Boot - 啟用HTTPS
- Spring Boot - Eureka 伺服器
- 使用Eureka註冊服務
- 閘道器代理伺服器和路由
- Spring Cloud 配置伺服器
- Spring Cloud 配置客戶端
- Spring Boot - Actuator
- Spring Boot - Admin 伺服器
- Spring Boot - Admin 客戶端
- Spring Boot - 啟用Swagger2
- Spring Boot - 使用SpringDoc OpenAPI
- Spring Boot - 建立Docker映象
- 追蹤微服務日誌
- Spring Boot - Flyway 資料庫
- Spring Boot - 傳送郵件
- Spring Boot - Hystrix
- Spring Boot - WebSocket
- Spring Boot - 批處理服務
- Spring Boot - Apache Kafka
- Spring Boot - Twilio
- Spring Boot - 單元測試用例
- Rest Controller 單元測試
- Spring Boot - 資料庫處理
- 保護Web應用程式
- Spring Boot - 基於JWT的OAuth2
- Spring Boot - Google Cloud Platform
- Spring Boot - Google OAuth2 登入
- Spring Boot 資源
- Spring Boot - 快速指南
- Spring Boot - 有用資源
- Spring Boot - 討論
Spring Boot - 基於JWT的OAuth2
本章將詳細講解Spring Boot安全機制以及基於JWT的OAuth2。
注意 - 此示例使用Spring Boot 1.5.9編寫。在Spring Boot 3中,Spring Security授權伺服器已棄用。
授權伺服器
授權伺服器是Web API安全性的一個高階架構元件。授權伺服器充當集中的授權點,允許您的應用程式和HTTP端點識別應用程式的功能。
資源伺服器
資源伺服器是一個向客戶端提供訪問令牌以訪問資源伺服器HTTP端點的應用程式。它是一組包含HTTP端點、靜態資源和動態網頁的庫。
OAuth2
OAuth2是一個授權框架,使應用程式Web安全能夠訪問客戶端的資源。要構建OAuth2應用程式,我們需要關注授權型別(授權碼)、客戶端ID和客戶端金鑰。
JWT令牌
JWT令牌是JSON Web令牌,用於表示雙方之間安全的宣告。您可以在www.jwt.io/瞭解更多關於JWT令牌的資訊。
現在,我們將構建一個OAuth2應用程式,該應用程式藉助JWT令牌啟用授權伺服器和資源伺服器的使用。
您可以使用以下步驟透過訪問資料庫來實現帶有JWT令牌的Spring Boot安全。
首先,我們需要在構建配置檔案中新增以下依賴項。
Maven使用者可以在您的pom.xml檔案中新增以下依賴項。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency>
Gradle使用者可以在build.gradle檔案中新增以下依賴項。
compile('org.springframework.boot:spring-boot-starter-security') compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') testCompile('org.springframework.security:spring-security-test') compile("org.springframework.security.oauth:spring-security-oauth2") compile('org.springframework.security:spring-security-jwt') compile("org.springframework.boot:spring-boot-starter-jdbc") compile("com.h2database:h2:1.4.191")
其中,
Spring Boot Starter Security - 實現Spring Security
Spring Security OAuth2 - 實現OAUTH2結構以啟用授權伺服器和資源伺服器。
Spring Security JWT - 為Web安全生成JWT令牌
Spring Boot Starter JDBC - 訪問資料庫以確保使用者是否存在。
Spring Boot Starter Web - 編寫HTTP端點。
H2資料庫 - 儲存用於身份驗證和授權的使用者的資訊。
完整的構建配置檔案如下所示。
pom.xml
<?xml version = "1.0" encoding = "UTF-8"?> <project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.tutorialspoint</groupId> <artifactId>websecurityapp</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>websecurityapp</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Gradle – build.gradle
buildscript { ext { springBootVersion = '1.5.9.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' group = 'com.tutorialspoint' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile('org.springframework.boot:spring-boot-starter-security') compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') testCompile('org.springframework.security:spring-security-test') compile("org.springframework.security.oauth:spring-security-oauth2") compile('org.springframework.security:spring-security-jwt') compile("org.springframework.boot:spring-boot-starter-jdbc") compile("com.h2database:h2:1.4.191") }
現在,在主要的Spring Boot應用程式中,新增`@EnableAuthorizationServer`和`@EnableResourceServer`註解,以便在同一個應用程式中充當身份驗證伺服器和資源伺服器。
此外,您可以使用以下程式碼編寫一個簡單的HTTP端點,以使用JWT令牌透過Spring Security訪問API。
WebsecurityappApplication.java
package com.tutorialspoint.websecurityapp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @EnableAuthorizationServer @EnableResourceServer @RestController public class WebsecurityappApplication { public static void main(String[] args) { SpringApplication.run(WebsecurityappApplication.class, args); } @RequestMapping(value = "/products") public String getProductName() { return "Honey"; } }
使用以下程式碼定義POJO類以儲存用於身份驗證的使用者的資訊。
UserEntity.java
package com.tutorialspoint.websecurityapp; import java.util.ArrayList; import java.util.Collection; import org.springframework.security.core.GrantedAuthority; public class UserEntity { private String username; private String password; private Collection<GrantedAuthority> grantedAuthoritiesList = new ArrayList<>(); public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Collection<GrantedAuthority> getGrantedAuthoritiesList() { return grantedAuthoritiesList; } public void setGrantedAuthoritiesList(Collection<GrantedAuthority> grantedAuthoritiesList) { this.grantedAuthoritiesList = grantedAuthoritiesList; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } }
現在,使用以下程式碼並定義CustomUser類,該類擴充套件org.springframework.security.core.userdetails.User類以進行Spring Boot身份驗證。
CustomUser.java
package com.tutorialspoint.websecurityapp; import org.springframework.security.core.userdetails.User; public class CustomUser extends User { private static final long serialVersionUID = 1L; public CustomUser(UserEntity user) { super(user.getUsername(), user.getPassword(), user.getGrantedAuthoritiesList()); } }
您可以建立`@Repository`類來從資料庫讀取使用者資訊並將其傳送到Custom使用者服務,還可以新增授予的許可權“ROLE_SYSTEMADMIN”。
OAuthDao.java
package com.tutorialspoint.websecurityapp; import java.sql.ResultSet; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.stereotype.Repository; @Repository public class OAuthDao { @Autowired private JdbcTemplate jdbcTemplate; public UserEntity getUserDetails(String username) { Collection<GrantedAuthority> grantedAuthoritiesList = new ArrayList<>(); String userSQLQuery = "SELECT * FROM USERS WHERE USERNAME=?"; List<UserEntity> list = jdbcTemplate.query(userSQLQuery, new String[] { username }, (ResultSet rs, int rowNum) -> { UserEntity user = new UserEntity(); user.setUsername(username); user.setPassword(rs.getString("PASSWORD")); return user; }); if (list.size() > 0) { GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_SYSTEMADMIN"); grantedAuthoritiesList.add(grantedAuthority); list.get(0).setGrantedAuthoritiesList(grantedAuthoritiesList); return list.get(0); } return null; } }
您可以建立一個Custom User detail service類,該類擴充套件org.springframework.security.core.userdetails.UserDetailsService以呼叫DAO儲存庫類,如下所示。
CustomDetailsService.java
package com.tutorialspoint.websecurityapp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; @Service public class CustomDetailsService implements UserDetailsService { @Autowired OAuthDao oauthDao; @Override public CustomUser loadUserByUsername(final String username) throws UsernameNotFoundException { UserEntity userEntity = null; try { userEntity = oauthDao.getUserDetails(username); CustomUser customUser = new CustomUser(userEntity); return customUser; } catch (Exception e) { e.printStackTrace(); throw new UsernameNotFoundException("User " + username + " was not found in the database"); } } }
接下來,建立一個`@configuration`類來啟用Web安全,定義密碼編碼器(BCryptPasswordEncoder),並定義AuthenticationManager bean。安全配置類應擴充套件WebSecurityConfigurerAdapter類。
SecurityConfiguration.java
package com.tutorialspoint.websecurityapp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private CustomDetailsService customDetailsService; @Bean public PasswordEncoder encoder() { return new BCryptPasswordEncoder(); } @Override @Autowired protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(customDetailsService).passwordEncoder(encoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated().and().sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.NEVER); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring(); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }
現在,定義OAuth2配置類以新增客戶端ID、客戶端金鑰、定義JwtAccessTokenConverter、私鑰和公鑰作為令牌簽名金鑰和驗證金鑰,併為具有作用域的令牌有效性配置ClientDetailsServiceConfigurer。
OAuth2Config.java
package com.tutorialspoint.websecurityapp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; @Configuration public class OAuth2Config extends AuthorizationServerConfigurerAdapter { private String clientid = "tutorialspoint"; private String clientSecret = "my-secret-key"; private String privateKey = "private key"; private String publicKey = "public key"; @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager; @Bean public JwtAccessTokenConverter tokenEnhancer() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey(privateKey); converter.setVerifierKey(publicKey); return converter; } @Bean public JwtTokenStore tokenStore() { return new JwtTokenStore(tokenEnhancer()); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore()) .accessTokenConverter(tokenEnhancer()); } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()"); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory().withClient(clientid).secret(clientSecret).scopes("read", "write") .authorizedGrantTypes("password", "refresh_token").accessTokenValiditySeconds(20000) .refreshTokenValiditySeconds(20000); } }
金鑰建立
現在,使用openssl建立私鑰和公鑰。
您可以使用以下命令生成私鑰。
openssl genrsa -out jwt.pem 2048 openssl rsa -in jwt.pem
您可以使用以下命令生成公鑰。
openssl rsa -in jwt.pem -pubout
對於高於1.5版本的Spring Boot,請在您的application.properties檔案中新增以下屬性以定義OAuth2資源過濾器順序。
security.oauth2.resource.filter-order=3
YAML檔案使用者可以在YAML檔案中新增以下屬性。
security: oauth2: resource: filter-order: 3
現在,在類路徑資源**src/main/resources/directory**下建立schema.sql和data.sql檔案以將應用程式連線到H2資料庫。
schema.sql檔案如下所示:
schema.sql
CREATE TABLE USERS (ID INT PRIMARY KEY, USERNAME VARCHAR(45), PASSWORD VARCHAR(60));
data.sql檔案如下所示:
data.sql
INSERT INTO USERS (ID, USERNAME,PASSWORD) VALUES ( 1, 'tutorialspoint@gmail.com','$2a$08$fL7u5xcvsZl78su29x1ti.dxI.9rYO8t0q5wk2ROJ.1cdR53bmaVG'); INSERT INTO USERS (ID, USERNAME,PASSWORD) VALUES ( 2, 'myemail@gmail.com','$2a$08$fL7u5xcvsZl78su29x1ti.dxI.9rYO8t0q5wk2ROJ.1cdR53bmaVG');
注意 - 密碼應以Bcrypt編碼器的格式儲存在資料庫表中。
編譯和執行
您可以建立一個可執行的JAR檔案,並使用以下Maven或Gradle命令執行Spring Boot應用程式。
對於Maven,您可以使用以下命令:
mvn clean install
“BUILD SUCCESS”之後,您可以在target目錄下找到JAR檔案。
對於Gradle,您可以使用如下所示的命令:
gradle clean build
“BUILD SUCCESSFUL”之後,您可以在build/libs目錄下找到JAR檔案。
現在,使用此處顯示的命令執行JAR檔案:
java –jar <JARFILE>
應用程式在Tomcat埠8080上啟動。

現在透過POSTMAN點選POST方法URL以獲取OAUTH2令牌。
https://:8080/oauth/token
現在,新增如下所示的請求頭:
Authorization - 使用您的客戶端ID和客戶端金鑰進行基本身份驗證。
Content Type - application/x-www-form-urlencoded

現在,新增如下所示的請求引數:
- grant_type = password
- username = 你的使用者名稱
- password = 你的密碼

現在,點選API並獲取access_token,如下所示:

現在,在請求頭中使用Bearer access token點選資源伺服器API,如下所示。

然後,您可以看到如下所示的輸出:
