반응형
오늘은 RESTful API에서 사용자 인증(Authentication)과 권한 부여(Authorization)를 구현하는 방법에 대해 학습합니다. API 보안을 강화하고, 역할(Role) 기반 접근 제어를 통해 민감한 데이터의 접근을 관리합니다.
1. 인증(Authentication)과 권한 관리의 이해
- 인증(Authentication)
사용자의 신원을 확인하는 과정입니다. 주로 사용자 이름, 비밀번호 또는 토큰을 사용합니다.- 예: 로그인, OAuth2.0 인증 등
- 권한 관리(Authorization)
인증된 사용자가 특정 리소스에 접근할 수 있는지를 확인합니다.- 예: 관리자만 특정 API를 호출 가능
2. Spring Security를 사용한 인증 구현
1) Spring Security 의존성 추가
pom.xml에 Spring Security 관련 의존성을 추가합니다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
2) Security 설정 클래스 작성
Spring Security의 기본 설정을 커스터마이징합니다.
import org.springframework.context.annotation.Bean;
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
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable() // CSRF 비활성화
.authorizeRequests()
.antMatchers("/api/public/**").permitAll() // 공개된 API
.antMatchers("/api/admin/**").hasRole("ADMIN") // 관리자 전용
.anyRequest().authenticated() // 나머지 요청 인증 필요
.and()
.httpBasic(); // HTTP Basic 인증
}
}
3. JWT를 활용한 인증
1) JWT란?
JWT(Json Web Token)는 사용자 인증 및 정보 교환에 사용되는 토큰 기반 인증 방식입니다.
구성: Header.Payload.Signature
2) JWT 토큰 생성 로직
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
public class JwtService {
private static final String SECRET_KEY = "mySecretKey";
private static final long EXPIRATION_TIME = 86400000; // 1일
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
}
3) JWT 인증 필터
사용자의 요청에 포함된 토큰을 검증하는 필터를 생성합니다.
import io.jsonwebtoken.Jwts;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private static final String SECRET_KEY = "mySecretKey";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
String jwt = token.substring(7);
try {
String username = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(jwt)
.getBody()
.getSubject();
if (username != null) {
Authentication auth = new CustomAuthentication(username);
SecurityContextHolder.getContext().setAuthentication(auth);
}
} catch (Exception e) {
SecurityContextHolder.clearContext();
}
}
filterChain.doFilter(request, response);
}
}
4. 권한(Role) 기반 접근 제어
1) 역할(Role) 설정
사용자마다 역할을 설정하여 리소스 접근을 제어합니다.
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.List;
public class User {
private String username;
private String password;
private List<GrantedAuthority> roles;
public User(String username, String password, List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles.stream()
.map(SimpleGrantedAuthority::new)
.toList();
}
// Getter & Setter 생략
}
2) 관리자 전용 API
@PreAuthorize 어노테이션을 사용하여 특정 역할만 접근 가능하게 설정합니다.
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/admin")
public class AdminController {
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/dashboard")
public String adminDashboard() {
return "관리자 대시보드";
}
}
5. 테스트
- 로그인 API 호출
사용자가 로그인을 통해 JWT 토큰을 발급받습니다. - POST /api/auth/login Headers: Content-Type: application/json Body: { "username": "admin", "password": "admin123" }
- JWT를 포함하여 요청 보내기
발급받은 JWT 토큰을 사용하여 인증된 요청을 보냅니다. - GET /api/admin/dashboard Headers: Authorization: Bearer <JWT 토큰>
- 권한 없는 사용자의 요청
관리자 전용 API에 접근하려는 일반 사용자는 403 Forbidden 응답을 받습니다.
6. 보안 최적화
- HTTPS 적용: 모든 데이터를 암호화하여 전송합니다.
- 토큰 만료 시간 설정: 짧은 만료 시간으로 보안 강화
- Refresh Token 사용: 만료된 액세스 토큰을 재발급합니다.
반응형
'개발 > 전자정부프레임워크' 카테고리의 다른 글
RESTful API 인증 및 권한 관리: 심화 과정 (0) | 2025.01.03 |
---|---|
RESTful API의 인증 및 권한 관리 구현:다음 단계 (0) | 2025.01.03 |
RESTful API의 검색 기능 구현 및 최적화 (0) | 2025.01.03 |
RESTful API에 인증과 권한 관리 추가하기 (0) | 2025.01.03 |
파일 업로드와 다운로드 기능 구현 (1) | 2025.01.03 |