Skip to content

Commit

Permalink
✨ Feat: WebSecurity 설정 및 Jwt 토큰 생성 기능 구현 (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
win-luck committed Oct 16, 2023
1 parent 229ac32 commit 39c628b
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.diareat.diareat.auth.component;

import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@RequiredArgsConstructor
public class JwtAuthFilter extends GenericFilterBean {

private final JwtTokenProvider jwtTokenProvider;

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 헤더에서 토큰 받아오기
String token = jwtTokenProvider.resolveToken((HttpServletRequest) request);

// 토큰이 유효하다면
if (token != null && jwtTokenProvider.validateToken(token)) {
// 토큰으로부터 유저 정보를 받아
Authentication authentication = jwtTokenProvider.getAuthentication(token);
// SecurityContext 에 객체 저장
SecurityContextHolder.getContext().setAuthentication(authentication);
}

// 다음 Filter 실행
chain.doFilter(request, response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.diareat.diareat.auth.component;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.Base64;
import java.util.Date;

@RequiredArgsConstructor
@Component
public class JwtTokenProvider {

@Value("${jwt.secret}")
private String secretKey;

private final UserDetailsService userDetailsService;

// 객체 초기화, secretKey를 Base64로 인코딩
@PostConstruct
protected void init() {
secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
}

// 토큰 생성
public String createToken(String userPk) {
Claims claims = Jwts.claims().setSubject(userPk); // JWT payload 에 저장되는 정보단위
Date now = new Date();
return Jwts.builder()
.setClaims(claims) // 정보 저장
.setIssuedAt(now) // 토큰 발행 시간 정보
.setExpiration(new Date(now.getTime() + (30 * 60 * 1000L))) // 토큰 유효시각 설정 (30분)
.signWith(SignatureAlgorithm.HS256, secretKey) // 암호화 알고리즘과, secret 값
.compact();
}

// 인증 정보 조회
public Authentication getAuthentication(String token) {
UserDetails userDetails = userDetailsService.loadUserByUsername(this.getUserPk(token));
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
}

// 토큰에서 회원 정보 추출
public String getUserPk(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
}

// 토큰 유효성, 만료일자 확인
public boolean validateToken(String jwtToken) {
try {
Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwtToken);
return !claims.getBody().getExpiration().before(new Date());
} catch (Exception e) {
return false;
}
}

// Request의 Header에서 token 값 가져오기
public String resolveToken(HttpServletRequest request) {
return request.getHeader("X-AUTH-TOKEN");
}
}
36 changes: 36 additions & 0 deletions src/main/java/com/diareat/diareat/config/WebSecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.diareat.diareat.config;

import com.diareat.diareat.auth.component.JwtAuthFilter;
import com.diareat.diareat.auth.component.JwtTokenProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@RequiredArgsConstructor
@EnableWebSecurity
public class WebSecurityConfig {

private final JwtTokenProvider jwtTokenProvider;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
//세션 사용 안함
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
//URL 관리
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll() // 이 API 는 누구나 접근 가능
.anyRequest().authenticated()
.and()
// JwtAuthenticationFilter를 먼저 적용
.addFilterBefore(new JwtAuthFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class);

return http.build();
}
}

0 comments on commit 39c628b

Please sign in to comment.