>  기사  >  Java  >  Spring Security로 마이크로서비스 보호: JWT 구현

Spring Security로 마이크로서비스 보호: JWT 구현

PHPz
PHPz원래의
2024-08-24 06:42:38398검색

JSON 웹 토큰(JWT)

JWT(JSON Web Token)는 두 당사자(예: 클라이언트와 서버) 간에 정보를 JSON 개체로 안전하게 전송하는 방법입니다. 컴팩트하고 URL 안전하도록 설계되어 URL, 헤더에서 쉽게 전달할 수 있습니다.

  1. 헤더
  2. 페이로드
  3. 서명

헤더
헤더는 일반적으로 토큰 유형(JWT)과 사용되는 서명 알고리즘(예: HMAC SHA256 또는 RSA)의 두 부분으로 구성됩니다.

{
"alg":"HS256",
"일반":"JWT"
}

페이로드
실제 데이터가 저장되는 곳입니다. 여기에는 사용자 ID, 역할, 만료 시간 및 기타 클레임(사용자 또는 세션에 대한 데이터)과 같은 정보가 포함될 수 있습니다.

{
"이메일":"ayushstwt@gmail.com",
"이름":"아유쉬"
}

서명
토큰의 무결성을 보장합니다. 이는 토큰이 변경되지 않았는지 확인하는 보안 기능입니다. 지정된 알고리즘을 사용하여 인코딩된 헤더와 페이로드를 비밀 키와 결합하여 생성됩니다. 서명은 서버가 토큰이 합법적이고 변조되지 않았는지 확인하는 데 도움이 됩니다.

JWT의 장점

자격 증명을 반복적으로 보낼 필요 없음: JWT를 사용하면 요청할 때마다 사용자 이름과 비밀번호를 보낼 필요가 없습니다. 대신, 한 번 로그인하면 서버가 토큰을 제공합니다. 그런 다음 귀하의 신원을 증명하기 위해 요청할 때마다 이 토큰을 보내 프로세스를 더욱 안전하고 효율적으로 만듭니다.

내장된 만료: 각 JWT에는 만료 시간이 있습니다. 즉, 특정 기간 동안만 유효합니다. 이렇게 하면 토큰이 어떻게든 가로채는 경우 장기간 오용될 위험이 줄어듭니다. 만료된 후에는 사용자가 다시 로그인하여 새 토큰을 받아야 보안이 강화됩니다.

Spring Boot를 사용하는 JWT는 로그인 후 토큰을 발급하여 사용자 인증을 안전하게 관리합니다. 이러한 토큰은 각 요청과 함께 전송되므로 자격 증명을 반복적으로 보내지 않고도 안전한 상태 비저장 통신을 보장합니다.

상태 비저장 통신은 서버가 과거 요청을 기억하지 않는다는 의미입니다. 각 요청은 JWT와 같이 필요한 모든 것을 전달하므로 서버는 세션 정보를 저장하지 않습니다.

Java Spring Boot 애플리케이션에서 JWT를 구현하려면 여러 단계가 필요합니다. 시작하기 위한 간단한 개요는 다음과 같습니다.

1. 종속성 추가

pom.xml 파일에 필요한 종속성을 포함하세요

                <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.12.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.12.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.12.5</version>
            <scope>runtime</scope>
        </dependency>

JWT를 사용하여 스프링 부트 애플리케이션을 생성하는 데 필요한 모든 종속성

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.tier3Hub</groupId>
    <artifactId>user-auth-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>user-auth-service</name>
    <description>The user-auth-service is a microservice responsible for handling user authentication and authorization within a distributed system. It is designed to manage user login, registration, and secure access to various services using robust security practices. This service implements authentication mechanisms like JSON Web Tokens (JWT) and integrates with OAuth 2.0 for third-party authentication. Built with Spring Boot, it ensures scalability, reliability, and easy integration with other microservices in the system.</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>21</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</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>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.12.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.12.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.12.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.modelmapper</groupId>
            <artifactId>modelmapper</artifactId>
            <version>3.1.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

우리는 다음과 같은 다양한 유형의 종속성을 사용하고 있습니다

  • 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 - RESTful 서비스를 포함한 웹 애플리케이션 구축을 지원합니다.
  • JJWT API: 0.12.5 - 안전한 토큰 관리를 위해 JWT 생성 및 구문 분석을 처리합니다.
  • JJWT Impl: 0.12.5 - 핵심 JWT 기능을 구현합니다.
  • JJWT Jackson: 0.12.5 - Jackson을 사용하여 JWT JSON 구문 분석을 활성화합니다.
  • MySQL 커넥터: 런타임 - 애플리케이션을 MySQL 데이터베이스에 연결합니다.
  • 롬복: 지정되지 않음 - 주석으로 상용구 코드를 줄입니다.
  • Spring Boot 스타터 테스트: 3.3.3 - Spring Boot 애플리케이션에 대한 테스트 지원을 제공합니다.
  • Spring Security Test: 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 파일에 구성을 추가하세요

spring.application.name=user-auth-service

server.port=8000

spring.datasource.url=jdbc:mysql://localhost:3306/auth_services
spring.datasource.username=root
spring.datasource.password=ayush@123

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

#debug logs
logging.level.org.springframework.security=debug

spring.main.allow-circular-references=true 

4. USER 엔터티 생성

package com.tier3Hub.user_auth_service.entity;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.List;

@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@Table
@Entity(name = "User")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    private String email;
    private String phoneNumber;
    private List<String> roles;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
}

** 5. 서비스, 저장소 클래스 및 인터페이스 생성**

Repository.java

package com.tier3Hub.user_auth_service.Repository;

import com.tier3Hub.user_auth_service.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface AuthRepository extends JpaRepository<User, Long> {

    User findByUsername(String username);
}

service.java

package com.tier3Hub.user_auth_service.service;

import com.tier3Hub.user_auth_service.dto.LoginResponse;
import com.tier3Hub.user_auth_service.dto.RegisterDTO;
import com.tier3Hub.user_auth_service.dto.RegisterResponse;

public interface AuthService {
    RegisterResponse register(RegisterDTO registerDTO);
}

6. 로그인, 로그인 요청 및 응답을 위한 DTO 생성

loginDTO.java 만들기

package com.tier3Hub.user_auth_service.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class LoginDTO {
    @NotBlank(message = "Username is required")
    @Size(min = 3, max = 20, message = "Username must be between 3 and 20 characters")
    private String username;

    @NotBlank(message = "Password is required")
    private String password;
}

loginResponse.java

package com.tier3Hub.user_auth_service.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LoginResponse {
    private String accessToken;
    private String tokenType = "Bearer";
}

DTO.java 등록

package com.tier3Hub.user_auth_service.dto;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class RegisterDTO {
    @NotBlank(message = "Username is required")
    @Size(min = 3, max = 20, message = "Username must be between 3 and 20 characters")
    private String username;

    @NotBlank(message = "Password is required")
    @Size(min = 8, message = "Password must be at least 8 characters")
    private String password;

    @NotBlank(message = "Email is required")
    @Email(message = "Email should be valid")
    private String email;
}

RegisterResponse.java

package com.tier3Hub.user_auth_service.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class RegisterResponse {
    private Long id;
    private String username;
    private String email;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
}

*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<Object> generateResponse(String message, HttpStatus status, Object responseObj) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("message", message);
        map.put("status", status.value());
        map.put("data", responseObj);
        return new ResponseEntity<Object>(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<String, Object> claims = new HashMap<>();
        return createToken(claims, username);
    }

    private String createToken(Map<String, Object> 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<Object> register(@Valid @RequestBody RegisterDTO registerDTO) {
        return ResponseHandler.generateResponse("User registered successfully", HttpStatus.OK, authService.register(registerDTO));
    }

    @PostMapping("/login")
    public ResponseEntity<Object> 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

프로젝트에서 Swagger를 사용하면 API 문서화 및 테스트가 향상됩니다. 개발자가 API를 탐색하고, 요청/응답 구조를 이해하고, 문서에서 직접 엔드포인트를 테스트할 수 있는 사용자 친화적인 인터페이스를 제공합니다. Swagger를 통합하면 코드 주석을 기반으로 API 문서의 자동 생성이 가능해 프런트엔드와 백엔드 개발자 모두 더 쉽게 효율적으로 협업할 수 있습니다.

Securing Microservices with Spring Security: Implementing JWT

먼저 사용자를 등록합니다

Securing Microservices with Spring Security: Implementing JWT

이런 반응을 얻습니다

Securing Microservices with Spring Security: Implementing JWT

그런 다음 사용자를 로그인합니다

Securing Microservices with Spring Security: Implementing JWT

이런 반응을 얻습니다

Securing Microservices with Spring Security: Implementing JWT

결론

이 프로젝트는 Spring Boot 애플리케이션에서 JWT(JSON 웹 토큰)를 사용하여 역할 기반 인증을 구현합니다. 이는 사용자가 등록하고 로그인할 수 있는 보안 인증 메커니즘을 갖추고 있으며 할당된 역할(예: USER 또는 ADMIN)에 따라 액세스 권한을 부여하는 JWT를 받습니다. SecurityConfig 클래스는 액세스 권한을 구성하여 중요한 작업을 승인된 사용자에게만 제한하면서 모든 사람이 공용 끝점에 액세스할 수 있도록 보장합니다. JWTUtil 클래스는 토큰 생성, 유효성 검사 및 사용자 추출을 처리합니다. 전반적으로 이 설정은 보안을 강화하여 애플리케이션 전반에 걸쳐 원활하고 강력한 액세스 제어를 가능하게 합니다.

이 프로젝트는 사용자 인증 및 권한 부여를 위해 Spring Security를 ​​활용하는 포괄적인 보안 프레임워크를 사용합니다. AuthController는 사용자 등록 및 로그인을 용이하게 하며 인증 성공 시 JWT를 생성합니다. 애플리케이션은 JWTFilter를 사용하여 요청을 가로채고 토큰의 유효성을 검사하므로 인증된 사용자만 보호된 리소스에 액세스할 수 있습니다. 역할 기반 액세스 제어를 통합함으로써 프로젝트는 유연하고 안전한 사용자 관리 시스템을 제공합니다. 이 디자인은 보안을 향상시킬 뿐만 아니라 반복적인 로그인 필요성을 최소화하여 사용자 경험도 향상시킵니다. 전반적으로 확장 가능하고 안전한 마이크로서비스를 구축하기 위한 견고한 기반을 마련합니다.

내 GitHub 저장소에서 사용자 인증 서비스의 전체 소스 코드를 탐색할 수 있습니다. 이 프로젝트에서는 인증을 위해 JWT를 사용한 사용자 등록, 로그인, 보안 액세스 등 다양한 기능을 선보입니다. 자유롭게 확인하고, 기여하고, 자신의 프로젝트에 참고 자료로 사용하세요!

GitHub 저장소: https://github.com/ishrivasayush/user-auth-service

JWT(JSON 웹 토큰)에 대해 더 자세히 알아보고 싶다면 jwt.io를 방문하는 것이 좋습니다. 이 리소스는 JWT의 작동 방식, 구조 및 실제 사례를 포함하여 JWT에 대한 포괄적인 정보를 제공합니다. 이는 최신 웹 애플리케이션에 필수적인 토큰 기반 인증 및 권한 부여를 이해하기 위한 훌륭한 출발점입니다. 초보자이거나 지식을 새로 고치려는 분이라면 jwt.io는 사용자 세션을 안전하게 관리하는 데 유용한 통찰력을 제공합니다.

위 내용은 Spring Security로 마이크로서비스 보호: JWT 구현의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.