우당탕탕

[Spring] 초보자를 위한 Spring Security: JWT로 웹 앱 보안 강화하기 본문

Tech/Spring

[Spring] 초보자를 위한 Spring Security: JWT로 웹 앱 보안 강화하기

모찌모찝 2024. 9. 14. 17:45

 

Spring Security를 활용하여 웹 애플리케이션의 인증 및 인가를 설정하고 JWT를 통한 보안 강화를 구현하는 방법

 

1. Spring Security란?

Spring Security는 Java 애플리케이션을 위한 강력하고 커스터마이징이 가능한 보안 프레임워크이다. 이 프레임워크는 웹 애플리케이션의 보안을 강화하는 데 필수적이며, 인증(Authentication)과 인가(Authorization) 기능을 제공한다.

2. 인증(Authentication)과 인가(Authorization) 

- 인증(Authentication)
사용자가 누구인지 확인하는 과정으로 예를 들어, 로그인 시 사용자가 입력한 아이디와 패스워드가 맞는지 검증하는 것을 인증이라 한다.

- 인가(Authorization)
인증된 사용자가 특정 리소스에 접근할 수 있는 권한이 있는지를 결정하는 과정을 인가라고 한다. 예를 들어, 관리자만 특정 페이지에 접근할 수 있도록 설정하는 것이 인가이다.

이 두 가지 개념이 웹 애플리케이션의 보안을 유지하는 데 핵심적인 역활을 한다.

3. Spring Security 기본 인증 설정

Spring Security를 사용하기 위해서는 먼저 Gradle과 Maven을 통해 의존성을 추가해야 한다.

Maven

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

 

Gradle

implementation 'org.springframework.boot:spring-boot-starter-security'

의존성 주입까지 완료되었다면 이제 Spring Security를 설정하기 위해 WebSecurityConfigurerAdapter를 상속받는 클래스를 생성한다. 이 클래스는 Spring Security의 설정을 커스터마이즈 할 수 있는 기본 구조를 제공하는 클래스이다.

WebSecurityConfigurerAdaper상속

import org.springframework.context.annotation.Configuration;
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.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity // Spring Security 기능을 활성화
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests() // 요청에 대한 권한 설정 시작
            .antMatchers("/public/**").permitAll() // /public/** URL은 인증 없이 접근 가능
            .antMatchers("/api/admin").hasRole("ADMIN") // ADMIN 권한이 필요
            .antMatchers("/api/user").hasRole("USER") // USER 권한이 필요
            .anyRequest().authenticated() // 나머지 요청은 인증이 필요함
            .and()
            .httpBasic(); // 기본 인증 사용
    }
}

위의 코드에서 사용한 것 처럼 @EnableWebSecurity를 활용하여 Spring Security 기능을 활성화시키고. antMatchers를 통해  해당 URL을 지정,. hasRole을 이용하여 권한에 대한 체크를 진행한다. (/**은 하위 경로를 모두 포함하는 것을 의미한다. 예를 들어 /public/sample , /public/mozzi 와 같은 url을 모두 포함한다)

4. JWT를 이용한 인증

JWT(JSON Web Token)는 사용자 인증을 위한 안전한 방법이다. 사용자가 로그인을 하면 서버는 JWT를 생성하여 클라이언트에 전달하고 이후 클라이언트는 이 토큰을 Authorization 헤더에 포함하여 요청하게 된다.

JWT 생성 예시

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

public String generateToken(String username) {
    return Jwts.builder()
            .setSubject(username) // 사용자 이름을 토큰의 주제로 설정
            .setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 1일 후 만료
            .signWith(SignatureAlgorithm.HS256, "secret-key") // 비밀 키로 서명
            .compact(); // 토큰 생성
}

위에서 작성한 generateToken을 활용해서 토큰 리턴하는 API를 간단하게 작성해보면 아래와 같다

import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api") // API 요청의 기본 경로
public class UserController {

    @PostMapping("/login") // 로그인 요청 처리
    public ResponseEntity<String> login(@RequestBody UserLoginDto loginDto) {
        // 사용자 인증 로직
        String token = generateToken(loginDto.getUsername()); // JWT 생성
        return ResponseEntity.ok(token); // 생성된 토큰 반환
    }

    @GetMapping("/user") // 사용자 정보 요청
    @PreAuthorize("hasRole('USER')") // USER 권한이 있어야 접근 가능
    public ResponseEntity<String> getUserInfo() {
        return ResponseEntity.ok("User Info"); // 사용자 정보 반환
    }
}

여기서 @PreAuthorize("hasRole('USER')")로 USER권한을 체크하게 되는데 어떤 사용자가 USER인지 판단은 어디서 하는 걸까?

@PreAuthorize 어노테이션이 붙은 메서드가 호출될 때, Spring Security는 현재 인증된 사용자의 UserDetails 객체를 확인하여 해당 사용자가 필요한 권한(예: USER, ADMIN)을 가지고 있는지를 판단하게 된다.

이처럼 Spring Security를 통해 웹 애플리케이션의 보안을 강화할 수 있다. 기본 인증을 설정하고, JWT를 사용하여 인증을 구현하며, 권한 관리를 통해 사용자 접근을 제어할 수 있으며, 이를 통해 보다 안전한 애플리케이션을 개발할 수 있다.

Comments