首頁> Java> java教程> 主體

使用 Spring Security 保護微服務:實施 JWT

PHPz
發布: 2024-08-24 06:42:38
原創
309 人瀏覽過

JSON 網路令牌 (JWT)

JWT(JSON Web Token)是一種以 JSON 物件的形式在兩方(例如客戶端和伺服器)之間安全傳輸資訊的方法。它的設計緊湊且 URL 安全,可以輕鬆地在 URL、標頭中傳遞。

  1. 標題
  2. 有效負載
  3. 簽名

標題
標頭通常由兩部分組成:令牌的類型 (JWT) 和所使用的簽章演算法,例如 HMAC SHA256 或 RSA。

{
"alg":"HS256",
“類型”:“JWT”
}

有效負載
這是實際資料儲存的地方。它可以包含使用者 ID、角色、過期時間和其他聲明(有關使用者或會話的資料)等資訊。

{
“電子郵件”:“ayushstwt@gmail.com”,
「名字」:「阿尤什」
}

簽名
確保令牌的完整性。這是一項安全功能,可確保令牌不被更改。它是透過使用指定演算法將編碼的標頭和有效負載與密鑰組合起來創建的。簽章幫助伺服器驗證token是否合法且未被竄改。

智威湯遜的優勢

無需重複發送憑證:使用 JWT,您不必在每次請求時都發送您的使用者名稱和密碼。相反,您登入一次,伺服器就會給您一個令牌。然後,您可以在每個請求中發送此令牌來證明您的身份,從而使該過程更加安全和高效。

內建過期時間:每個 JWT 都有一個過期時間,這意味著它僅在特定期限內有效。如果令牌以某種方式被攔截,這可以降低長期濫用的風險。過期後,使用者需要重新登入才能取得新的令牌,增加了額外的安全層。

JWT 與 Spring Boot 透過在登入後頒發令牌來安全地管理使用者身份驗證。這些令牌隨每個請求一起發送,確保安全、無狀態的通信,而無需重複發送憑證。

無狀態通訊意味著伺服器不記得過去的請求。每個請求都攜帶所需的一切(如 JWT),因此伺服器不會儲存會話資訊。

在 Java Spring Boot 應用程式中實作 JWT 涉及幾個步驟。以下是幫助您入門的簡化大綱:

1.新增依賴項

在 pom.xml 檔案中包含必要的依賴項

雷雷

我們使用 JWT 創建 spring-boot 應用程式所需的所有相依性

雷雷

我們正在使用不同類型的依賴項,例如

  • Spring Boot Starter Actuator:3.3.3 - 新增生產就緒功能,例如監控和運作狀況檢查。
  • Spring Boot Starter Data JPA:3.3.3 - 透過 JPA 支援簡化資料庫互動。
  • Spring Boot Starter Security:3.3.3 - 提供身份驗證和授權等安全功能。
  • Spring Boot Starter Web:3.3.3 - 支援建立 Web 應用程序,包括 RESTful 服務。
  • JJWT API:0.12.5 - 處理 JWT 建立和解析以實現安全令牌管理。
  • JJWT Impl:0.12.5 - 實作核心 JWT 功能。
  • JJWT Jackson:0.12.5 - 使用 Jackson 啟用 JWT JSON 解析。
  • MySQL 連接器:執行階段 - 將您的應用程式連接到 MySQL 資料庫。
  • Lombok:未指定 - 透過註解減少樣板程式碼。
  • Spring Boot Starter Test:3.3.3 - 為 Spring Boot 應用程式提供測試支援。
  • Spring 安全測試:3.3.3 - 協助測試安全配置。
  • Spring Boot Starter 驗證:3.3.3 - 新增對請求和回應物件的驗證支援。
  • SpringDoc OpenAPI Starter WebMVC UI:2.5.0 - 整合了 API 文件的 Swagger UI。
  • ModelMapper:3.1.1 - 簡化不同層之間的物件映射。

*2。專案結構*

Securing Microservices with Spring Security: Implementing JWT

3.在application.properties檔案中新增設定

雷雷

4.建立 USER 實體

雷雷

** 5.建立服務和儲存庫類別和介面**

Repository.java

雷雷

服務.java

雷雷

6。建立 DTO 用於登入、登入請求和回應

創建loginDTO.java

雷雷

loginResponse.java

雷雷

註冊DTO.java

雷雷

RegisterResponse.java

雷雷

*7。為了從 API 發送自訂回應,我們使用 ResponseHandler.java *

package com.tier3Hub.user_auth_service.utils; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import java.util.HashMap; import java.util.Map; public class ResponseHandler { public static ResponseEntity generateResponse(String message, HttpStatus status, Object responseObj) { Map map = new HashMap(); map.put("message", message); map.put("status", status.value()); map.put("data", responseObj); return new ResponseEntity(map, status); } }
        
登入後複製

8. for storing some constants we create the class inside the utils package that is ApplicationConstants.java

package com.tier3Hub.user_auth_service.utils; public class AppConstants { public static final String[] PUBLIC_URLS = { "/v3/api-docs/**", "/swagger-ui/**", "/api/auth/register/**", "/api/auth/login/**","/api/auth/registerAdmin/**" }; }
登入後複製

9. for converting the object one to another we use the dependency that is model mapper for configuration that we create the class inside the config package that is ApplicationConfigs.java

package com.tier3Hub.user_auth_service.config; import org.modelmapper.ModelMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ApplicationConfigs { @Bean public ModelMapper modelMapper() { return new ModelMapper(); } }
登入後複製

**
This is the basic setup that we do for every spring-boot application we create now securing the rest endpoint with JWT we started.
**

now inside the security package we create the class called JWTFilter.java

The JWTFilter is a custom Spring Security filter that intercepts HTTP requests to validate JWTs. It checks for the "Authorization" header, extracts the token, and retrieves the username. If the token is valid, it creates an authentication token with user details and sets it in the security context, allowing the application to recognize the authenticated user for further processing.

package com.tier3Hub.user_auth_service.security; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Service; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; @Service public class JWTFilter extends OncePerRequestFilter { @Autowired private UserDetailsService userDetailsService; @Autowired private JWTUtil jwtUtil; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String authorizationHeader = request.getHeader("Authorization"); String username = null; String jwt = null; if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { jwt = authorizationHeader.substring(7); username = jwtUtil.extractUsername(jwt); } if (username != null) { UserDetails userDetails = userDetailsService.loadUserByUsername(username); if (jwtUtil.validateToken(jwt)) { UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(auth); } } chain.doFilter(request, response); } }
登入後複製

create the class JWTUtil.java

The JWTUtil class manages JWT operations, including extracting usernames and expiration dates from tokens. It generates new tokens using a secret key and validates existing tokens by checking their expiration. The class uses HMAC for signing and includes methods to parse claims and determine if tokens are expired, ensuring secure authentication and authorization in the application.

package com.tier3Hub.user_auth_service.security; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import org.springframework.stereotype.Service; import javax.crypto.SecretKey; import java.util.Date; import java.util.HashMap; import java.util.Map; @Service public class JWTUtil { private String SECRET_KEY = "TaK+HaV^uvCHEFsEVfypW#7g9^k*Z8$V"; private SecretKey getSigningKey() { return Keys.hmacShaKeyFor(SECRET_KEY.getBytes()); } public String extractUsername(String token) { Claims claims = extractAllClaims(token); return claims.getSubject(); } public Date extractExpiration(String token) { return extractAllClaims(token).getExpiration(); } private Claims extractAllClaims(String token) { return Jwts.parser() .verifyWith(getSigningKey()) .build() .parseSignedClaims(token) .getPayload(); } private Boolean isTokenExpired(String token) { return extractExpiration(token).before(new Date()); } public String generateToken(String username) { Map claims = new HashMap<>(); return createToken(claims, username); } private String createToken(Map claims, String subject) { return Jwts.builder() .claims(claims) .subject(subject) .header().empty().add("typ","JWT") .and() .issuedAt(new Date(System.currentTimeMillis())) .expiration(new Date(System.currentTimeMillis() + 1000 * 60 * 50)) // 5 minutes expiration time .signWith(getSigningKey()) .compact(); } public Boolean validateToken(String token) { return !isTokenExpired(token); } }
登入後複製

*configure the Spring security and add some modifictaion we create the class SecurityConfig.java *

The SecurityConfig class sets up security for the application using Spring Security. It defines access rules, allowing public endpoints while restricting others based on user roles. The class incorporates a JWT filter to validate tokens and uses BCrypt for password encoding. It also configures an authentication manager with a custom user details service for secure user authentication.

package com.tier3Hub.user_auth_service.config; import com.tier3Hub.user_auth_service.security.JWTFilter; import com.tier3Hub.user_auth_service.service.UserInfoConfigManager; import com.tier3Hub.user_auth_service.utils.AppConstants; 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.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity public class SecurityConfig { @Autowired private JWTFilter jwtFilter; @Autowired private UserInfoConfigManager userInfoConfigManager; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http.authorizeHttpRequests(request -> request .requestMatchers(AppConstants.PUBLIC_URLS).permitAll() .requestMatchers("/api/test/public/hello/**").hasAnyRole("USER","ADMIN") .requestMatchers("/api/test/private/**").hasRole("ADMIN") .anyRequest() .authenticated()) .csrf(AbstractHttpConfigurer::disable) .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class) .build(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userInfoConfigManager).passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration auth) throws Exception { return auth.getAuthenticationManager(); } }
登入後複製

The securityFilterChain method configures access rules for different API endpoints in the Spring application. It permits public URLs and applies role-based access control for user and admin roles. Role-based authentication restricts resource access based on user roles (e.g., USER, ADMIN). In Spring Boot, you define roles and configure security settings in the SecurityConfig class to specify access permissions. During user registration, assign roles, and use annotations like @PreAuthorize to enforce role checks in controllers. This approach enhances security, allows easy permission management, and simplifies user access rights as the application scales. Implementing role-based auth provides flexibility and maintainability for your user management system. CSRF protection is disabled, and a custom JWT filter is added to authenticate requests based on JSON Web Tokens, ensuring secure and controlled access to resources.

configureGlobal method handle configures global authentication settings in a Spring application. It uses a custom user details service for loading user data and a BCrypt password encoder for secure password hashing. Additionally, it provides an AuthenticationManager bean for handling authentication processes, ensuring a secure and efficient user authentication system that leverages strong password management practices.

create the endpoints for register and login

package com.tier3Hub.user_auth_service.Controller; import com.tier3Hub.user_auth_service.dto.LoginDTO; import com.tier3Hub.user_auth_service.dto.LoginResponse; import com.tier3Hub.user_auth_service.dto.RegisterDTO; import com.tier3Hub.user_auth_service.security.JWTUtil; import com.tier3Hub.user_auth_service.service.AuthService; import com.tier3Hub.user_auth_service.service.UserInfoConfigManager; import com.tier3Hub.user_auth_service.utils.ResponseHandler; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/auth") public class AuthController { @Autowired JWTUtil jwtUtil; @Autowired AuthService authService; @Autowired AuthenticationManager authenticationManager; @Autowired private UserInfoConfigManager userInfoConfigManager; @PostMapping("/register") public ResponseEntity register(@Valid @RequestBody RegisterDTO registerDTO) { return ResponseHandler.generateResponse("User registered successfully", HttpStatus.OK, authService.register(registerDTO)); } @PostMapping("/login") public ResponseEntity login(@Valid @RequestBody LoginDTO loginDTO) { try { Authentication authenticate = authenticationManager .authenticate(new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword())); UserDetails userDetails = userInfoConfigManager.loadUserByUsername(loginDTO.getUsername()); String jwt = jwtUtil.generateToken(userDetails.getUsername()); LoginResponse loginResponse = LoginResponse .builder() .accessToken(jwt) .build(); return ResponseHandler.generateResponse("User logged in successfully", HttpStatus.OK, loginResponse); } catch (Exception e) { return new ResponseEntity<>("Incorrect username or password", HttpStatus.BAD_REQUEST); } } }
        
登入後複製

This login method in the AuthController handles user login requests. It takes a LoginDTO containing the username and password, validates them, and attempts authentication using the AuthenticationManager. Upon successful authentication, it retrieves user details and generates a JWT token using the JWTUtil class. The token is then included in a LoginResponse object and returned with a success message. If authentication fails, it catches the exception and returns a "Incorrect username or password" response with a 400 status code.

generateToken(String username):This method creates an empty claims map and calls the createToken method with the username as the subject. It serves as the entry point for token generation.

c*reateToken(Map claims, String subject):* This method builds the JWT using the Jwts.builder(). It sets the claims, subject, and token metadata, such as issue date and expiration time (set to 5 minutes). The token is then signed with a secret key and compacted into a string format for transmission.

Testing

now we run the application

Securing Microservices with Spring Security: Implementing JWT

and hit the URL here our application is runing on 8000 port

http://localhost:8000/swagger-ui/index.html

Menggunakan Swagger dalam projek anda meningkatkan dokumentasi dan ujian API. Ia menyediakan antara muka mesra pengguna untuk pembangun meneroka API anda, memahami struktur permintaan/tindak balas dan menguji titik akhir terus daripada dokumentasi. Dengan menyepadukan Swagger, anda mendayakan penjanaan automatik dokumen API berdasarkan anotasi kod anda, menjadikannya lebih mudah untuk pembangun bahagian hadapan dan belakang untuk bekerjasama dengan cekap.

Securing Microservices with Spring Security: Implementing JWT

mula-mula kami daftarkan pengguna

Securing Microservices with Spring Security: Implementing JWT

kami dapat sambutan seperti ini

Securing Microservices with Spring Security: Implementing JWT

selepas itu kami login pengguna

Securing Microservices with Spring Security: Implementing JWT

kami dapat sambutan seperti ini

Securing Microservices with Spring Security: Implementing JWT

Kesimpulan

Projek ini melaksanakan pengesahan berasaskan peranan menggunakan JWT (Token Web JSON) dalam aplikasi Spring Boot. Ia menampilkan mekanisme pengesahan selamat di mana pengguna boleh mendaftar dan log masuk, menerima JWT yang memberikan akses berdasarkan peranan yang diberikan mereka (seperti USER atau ADMIN). Kelas SecurityConfig mengkonfigurasi kebenaran akses, memastikan titik akhir awam boleh diakses oleh semua orang sambil mengehadkan operasi sensitif kepada pengguna yang dibenarkan sahaja. Kelas JWTUtil mengendalikan penciptaan token, pengesahan dan pengekstrakan pengguna. Secara keseluruhan, persediaan ini meningkatkan keselamatan, membolehkan kawalan akses yang lancar dan mantap merentas aplikasi.

Projek ini menggunakan rangka kerja keselamatan komprehensif yang memanfaatkan Spring Security untuk pengesahan dan kebenaran pengguna. AuthController memudahkan pendaftaran dan log masuk pengguna, menghasilkan JWT apabila pengesahan berjaya. Aplikasi ini menggunakan JWTFilter untuk memintas permintaan dan mengesahkan token, memastikan bahawa hanya pengguna yang disahkan boleh mengakses sumber yang dilindungi. Dengan menyepadukan kawalan akses berasaskan peranan, projek ini menyediakan sistem pengurusan pengguna yang fleksibel dan selamat. Reka bentuk ini bukan sahaja meningkatkan keselamatan tetapi juga meningkatkan pengalaman pengguna dengan meminimumkan keperluan untuk log masuk berulang. Secara keseluruhannya, ia meletakkan asas yang kukuh untuk membina perkhidmatan mikro berskala dan selamat.

Anda boleh menerokai kod sumber lengkap untuk Perkhidmatan Pengesahan Pengguna pada repositori GitHub saya. Projek ini mempamerkan pelbagai ciri seperti pendaftaran pengguna, log masuk dan akses selamat menggunakan JWT untuk pengesahan. Jangan ragu untuk menyemaknya, menyumbang atau menggunakannya sebagai rujukan untuk projek anda sendiri!

Repositori GitHub: https://github.com/ishrivasayush/user-auth-service

Bagi mereka yang berminat untuk menyelam lebih dalam ke dalam JSON Web Token (JWT), saya syorkan melawati jwt.io. Sumber ini menyediakan maklumat komprehensif tentang JWT, termasuk cara ia berfungsi, strukturnya dan contoh praktikal. Ia merupakan titik permulaan yang sangat baik untuk memahami pengesahan dan kebenaran berasaskan token, yang penting untuk aplikasi web moden. Sama ada anda seorang pemula atau ingin menyegarkan pengetahuan anda, jwt.io menawarkan cerapan berharga dalam mengurus sesi pengguna dengan selamat.

以上是使用 Spring Security 保護微服務:實施 JWT的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!