티스토리 뷰
728x90
반응형
JWT 설정 방법
- 단계: JwtProvider 생성
- 단계: JwtAuthenticationFilter 생성
- 단계: SecurityConfig 생성
- 단계: 인증 및 토큰 생성
- 단계: JwtProvider 생성
application.properties 설정
# JWT 설정
jwt.secret=SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
jwt.expirationMillis=86400000
pom.xml 설정
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.3</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.3</version>
<scope>runtime</scope>
</dependency>
JwtProvider.java
package com.example.demo.provider;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
@Component
public class JwtProvider {
private final SecretKey secretKey;
private final long expirationMillis;
public JwtProvider(@Value("${jwt.secret}") String secret, @Value("${jwt.expirationMillis}") long expirationMillis) {
this.secretKey = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
this.expirationMillis = expirationMillis;
}
public String generateToken(String subject) {
return Jwts.builder()
.subject(subject)
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + expirationMillis))
.signWith(secretKey)
.compact();
}
public String extractUsername(String token) {
return Jwts.parser()
.verifyWith(secretKey)
.build()
.parseSignedClaims(token)
.getPayload()
.getSubject();
}
public boolean validateToken(String token) {
try {
Jwts.parser()
.verifyWith(secretKey)
.build()
.parseSignedClaims(token);
return true;
} catch (Exception e) {
return false;
}
}
}
2. 단계: JwtAuthenticationFilter 생성
package com.example.demo.filter;
import com.example.demo.dto.ApiResult;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import com.example.demo.provider.JwtProvider;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.Optional;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtProvider jwtProvider;
private final UserService userService;
public JwtAuthenticationFilter(JwtProvider jwtProvider, UserService userService) {
this.jwtProvider = jwtProvider;
this.userService = userService;
}
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
) throws ServletException, IOException {
try {
extractToken(request)
.filter(jwtProvider::validateToken)
.map(jwtProvider::extractUsername)
.flatMap(userService::findByEmail)
.ifPresent(this::setAuthentication);
filterChain.doFilter(request, response);
} catch (UsernameNotFoundException ex) {
handleException(response, "User not found: " + ex.getMessage(), HttpStatus.NOT_FOUND);
} catch (Exception ex) {
handleException(response, "Authentication error: " + ex.getMessage(), HttpStatus.UNAUTHORIZED);
}
}
private Optional<String> extractToken(HttpServletRequest request) {
String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
return Optional.of(header.substring(7));
}
return Optional.empty();
}
private void setAuthentication(User user) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
user, null, user.getAuthorities()
);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
// 예외 응답 처리 메서드 추가
private void handleException(HttpServletResponse response, String message, HttpStatus status) throws IOException {
ApiResult<Void> apiResult = new ApiResult<>(false, message, null);
response.setStatus(status.value());
response.setContentType("application/json");
response.getWriter().write(new ObjectMapper().writeValueAsString(apiResult));
}
}
3. 단계: SecurityConfig 생성
package com.example.demo.config;
import com.example.demo.filter.JwtAuthenticationFilter;
import lombok.RequiredArgsConstructor;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
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
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthenticationFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// 기본 HTTP 인증과 CSRF 보호 비활성화
.httpBasic(AbstractHttpConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable)
// JWT 기반 인증을 사용하므로 상태 없는 세션 정책 적용
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// URL 접근 권한 설정
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll() // 인증이 필요없는 경로
.anyRequest().authenticated() // 그 외 모든 요청은 인증 필요
)
// JWT 인증 필터를 UsernamePasswordAuthenticationFilter 이전에 실행
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
4단계: 인증 및 토큰 생성
package com.example.demo.controller;
import com.example.demo.dto.ApiResult;
import com.example.demo.dto.SignUpRequestDTO;
import com.example.demo.dto.sign.in.SignInRequestDTO;
import com.example.demo.dto.sign.in.SignInResponseDTO;
import com.example.demo.entity.User;
import com.example.demo.provider.JwtProvider;
import com.example.demo.service.UserService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import java.util.Set;
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
private final UserService userService;
private final PasswordEncoder passwordEncoder;
private final JwtProvider jwtUtils;
@PostMapping("/signIn")
public ResponseEntity<ApiResult<SignInResponseDTO>> signIn(@RequestBody @Valid SignInRequestDTO request) {
return userService.findByEmail(request.getEmail())
.filter(user -> passwordEncoder.matches(request.getPassword(), user.getPassword()))
.map(user -> {
String token = jwtUtils.generateToken(request.getEmail());
SignInResponseDTO responseDTO = new SignInResponseDTO();
responseDTO.setToken(token);
return ResponseEntity.ok(new ApiResult<>(true, "Success", responseDTO));
})
.orElseGet(() -> ResponseEntity.ok(new ApiResult<>(false, "이메일 또는 비밀번호가 올바르지 않습니다.", null)));
}
}
728x90
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- system.io
- 특정 문자를 기준으로 자르기
- 메이븐(maven)
- REST API
- java.sql
- error-java
- 인텔리제이(intellij)
- 표현 언어(expression language)
- docker
- 진수 변환
- 스프링 시큐리티(spring security)
- jsp 오픈 소스
- 문자 자르기
- 스프링 시큐리티(spring security)-http basic 인증
- System.Diagnostics
- 스프링 프레임워크(spring framewordk)
- MainActor
- React
- 람다식(lambda expression)
- await
- 제품 등록
- java web-mvc
- In App Purchase
- java 키워드 정리
- jstl(java standard tag library)
- 스프링 프레임워크(spring framework)
- nl2br
- jstl(java standard tag library)-core
- java-개발 환경 설정하기
- .submit()
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
글 보관함