-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat : OAuth2.0 카카오 로그인 & JWT 인증 구현 #18
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
25e4eee
chore: OAuth2.0 의존성 추가
kkangh00n 8281ed2
feat : Member 도메인 email 필드 추가 & 알림 여부 기본값 true로 초기화
kkangh00n 81722d6
feat : 소셜 로그인 사용자 정보 조회
kkangh00n ab72dac
feat : 소셜 로그인 사용자 가입 여부 확인 후 저장
kkangh00n 55a743c
feat : OAuth2.0 커스텀 로직 적용
kkangh00n 099c460
chore : JWT 의존성 추가
kkangh00n ca90a5f
feat : JWT properties 객체
kkangh00n 708f602
feat : 회원 로그인 시 JWT 토큰 발급
kkangh00n c72c081
feat : 로그인 완료 후 발급된 JWT 토큰을 JSON으로 전달
kkangh00n 6843ab0
feat : RefreshToken 저장을 위한 테이블 생성
kkangh00n c7d91a4
feat : 로그인 시, RefreshToken 테이블에 저장
kkangh00n 459dac8
feat : 인가를 위해 Member Role 필드 추가
kkangh00n efc32e1
feat : 요청 시, JWT 토큰을 이용한 사용자 인증 필터 구현
kkangh00n a97bccc
feat : JwtAuthenticationFilter 적용
kkangh00n 63b6a88
fix : 누락 메서드 추가
kkangh00n d2e967f
style : 인덴트 컨벤션 수정
kkangh00n 86ea017
refactor : 누락 접근 제어자 추가
kkangh00n e177ee5
chore : conflict resolve
kkangh00n 8db399f
chore : conflict resolve
kkangh00n 4b3136b
chore : conflict resolve
kkangh00n c00daa5
chore : conflict resolve
kkangh00n 0495100
chore : conflict resolve
kkangh00n f7799fe
chore : conflict resolve
kkangh00n File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package com.prgrms.catchtable.common; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public enum Role { | ||
|
||
MEMBER("ROLE_MEMBER"), | ||
OWNER("ROLE_OWNER"); | ||
|
||
private final String role; | ||
} |
16 changes: 16 additions & 0 deletions
16
src/main/java/com/prgrms/catchtable/jwt/config/JwtConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.prgrms.catchtable.jwt.config; | ||
|
||
import lombok.Data; | ||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
@Data | ||
@ConfigurationProperties(prefix = "jwt") | ||
public class JwtConfig { | ||
|
||
private String clientSecret; | ||
private int expiryMinute; | ||
private int expiryMinuteRefresh; | ||
|
||
} |
35 changes: 35 additions & 0 deletions
35
src/main/java/com/prgrms/catchtable/jwt/domain/RefreshToken.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.prgrms.catchtable.jwt.domain; | ||
|
||
import static lombok.AccessLevel.PROTECTED; | ||
|
||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@NoArgsConstructor(access = PROTECTED) | ||
@Entity | ||
public class RefreshToken { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@Column(name = "token") | ||
private String token; | ||
|
||
@Column(name = "email") | ||
private String email; | ||
|
||
@Builder | ||
public RefreshToken(String token, String email) { | ||
this.token = token; | ||
this.email = email; | ||
} | ||
|
||
} |
64 changes: 64 additions & 0 deletions
64
src/main/java/com/prgrms/catchtable/jwt/filter/JwtAuthenticationFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package com.prgrms.catchtable.jwt.filter; | ||
|
||
import com.prgrms.catchtable.jwt.domain.RefreshToken; | ||
import com.prgrms.catchtable.jwt.provider.JwtTokenProvider; | ||
import com.prgrms.catchtable.jwt.service.RefreshTokenService; | ||
import com.prgrms.catchtable.jwt.token.Token; | ||
import jakarta.servlet.FilterChain; | ||
import jakarta.servlet.GenericFilter; | ||
import jakarta.servlet.ServletException; | ||
import jakarta.servlet.ServletRequest; | ||
import jakarta.servlet.ServletResponse; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import java.io.IOException; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.security.core.context.SecurityContextHolder; | ||
import org.springframework.security.core.userdetails.UsernameNotFoundException; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class JwtAuthenticationFilter extends GenericFilter { | ||
|
||
private final JwtTokenProvider jwtTokenProvider; | ||
|
||
private final RefreshTokenService refreshTokenService; | ||
|
||
@Override | ||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | ||
throws IOException, ServletException { | ||
|
||
String accessToken = ((HttpServletRequest) request).getHeader("AccessToken"); | ||
String refreshToken = ((HttpServletRequest) request).getHeader("RefreshToken"); | ||
|
||
if (accessToken != null) { | ||
//AccessToken 유효 | ||
if (jwtTokenProvider.validateToken(accessToken)) { | ||
setAuthentication(accessToken); | ||
} | ||
//RefreshToken 유효 | ||
else { | ||
if (jwtTokenProvider.validateToken(refreshToken)) { | ||
RefreshToken refreshTokenEntity = refreshTokenService.getRefreshTokenByToken( | ||
refreshToken); | ||
String email = refreshTokenEntity.getEmail(); | ||
Token newToken = jwtTokenProvider.createToken(email); | ||
|
||
((HttpServletResponse) response).setHeader("AccessToken", | ||
newToken.getAccessToken()); | ||
setAuthentication(newToken.getAccessToken()); | ||
} else { | ||
throw new UsernameNotFoundException("Please Login again"); | ||
} | ||
} | ||
} | ||
chain.doFilter(request, response); | ||
} | ||
|
||
private void setAuthentication(String accessToken) { | ||
Authentication authentication = jwtTokenProvider.getAuthentication(accessToken); | ||
SecurityContextHolder.getContext().setAuthentication(authentication); | ||
} | ||
} |
90 changes: 90 additions & 0 deletions
90
src/main/java/com/prgrms/catchtable/jwt/provider/JwtTokenProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package com.prgrms.catchtable.jwt.provider; | ||
|
||
|
||
import com.prgrms.catchtable.jwt.config.JwtConfig; | ||
import com.prgrms.catchtable.jwt.service.JwtUserDetailsService; | ||
import com.prgrms.catchtable.jwt.token.Token; | ||
import io.jsonwebtoken.Claims; | ||
import io.jsonwebtoken.JwtException; | ||
import io.jsonwebtoken.Jwts; | ||
import io.jsonwebtoken.SignatureAlgorithm; | ||
import java.util.Date; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.security.core.userdetails.UserDetails; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class JwtTokenProvider { | ||
|
||
private final JwtConfig jwtConfig; | ||
|
||
private final JwtUserDetailsService jwtUserDetailsService; | ||
|
||
public Token createToken(String email) { | ||
|
||
Claims claims = Jwts.claims().setSubject(email); | ||
Date now = new Date(); | ||
|
||
String accessToken = createAccessToken(claims, now); | ||
String refreshToken = createRefreshToken(claims, now); | ||
|
||
return new Token(accessToken, refreshToken, email); | ||
} | ||
|
||
private String createAccessToken(Claims claims, Date now) { | ||
long expiryMinute = jwtConfig.getExpiryMinute() * 1000L * 60; | ||
|
||
return Jwts.builder() | ||
.setClaims(claims) | ||
.setIssuedAt(now) | ||
.setExpiration(new Date(now.getTime() + expiryMinute)) | ||
.signWith(SignatureAlgorithm.HS256, jwtConfig.getClientSecret()) | ||
.compact(); | ||
} | ||
|
||
private String createRefreshToken(Claims claims, Date now) { | ||
|
||
long expiryMinuteRefresh = jwtConfig.getExpiryMinuteRefresh() * 1000L * 60; | ||
|
||
return Jwts.builder() | ||
.setClaims(claims) | ||
.setIssuedAt(now) | ||
.setExpiration(new Date(now.getTime() + expiryMinuteRefresh)) | ||
.signWith(SignatureAlgorithm.HS256, jwtConfig.getClientSecret()) | ||
.compact(); | ||
} | ||
|
||
public boolean validateToken(String token) { | ||
try { | ||
Claims claims = Jwts.parserBuilder() | ||
.setSigningKey(jwtConfig.getClientSecret()) | ||
.build() | ||
.parseClaimsJws(token) | ||
.getBody(); | ||
|
||
return claims.getExpiration().after(new Date()); | ||
} catch (JwtException je) { | ||
return false; | ||
} | ||
} | ||
|
||
public Authentication getAuthentication(String token) { | ||
String email = getEmail(token); | ||
UserDetails userDetails = jwtUserDetailsService.loadUserByUsername(email); | ||
return new UsernamePasswordAuthenticationToken(userDetails, "", | ||
userDetails.getAuthorities()); | ||
} | ||
|
||
private String getEmail(String token) { | ||
Claims claims = Jwts.parserBuilder() | ||
.setSigningKey(jwtConfig.getClientSecret()) | ||
.build() | ||
.parseClaimsJws(token) | ||
.getBody(); | ||
|
||
return claims.getSubject(); | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
src/main/java/com/prgrms/catchtable/jwt/repository/RefreshTokenRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package com.prgrms.catchtable.jwt.repository; | ||
|
||
import com.prgrms.catchtable.jwt.domain.RefreshToken; | ||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> { | ||
|
||
boolean existsRefreshTokenByEmail(String email); | ||
|
||
void deleteRefreshTokenByEmail(String email); | ||
|
||
Optional<RefreshToken> findRefreshTokenByToken(String token); | ||
} |
21 changes: 21 additions & 0 deletions
21
src/main/java/com/prgrms/catchtable/jwt/service/JwtUserDetailsService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.prgrms.catchtable.jwt.service; | ||
|
||
import com.prgrms.catchtable.member.repository.MemberRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.core.userdetails.UserDetails; | ||
import org.springframework.security.core.userdetails.UserDetailsService; | ||
import org.springframework.security.core.userdetails.UsernameNotFoundException; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class JwtUserDetailsService implements UserDetailsService { | ||
|
||
private final MemberRepository memberRepository; | ||
|
||
@Override | ||
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { | ||
return memberRepository.findMemberByEmail(email) | ||
.orElseThrow(() -> new UsernameNotFoundException("Not Found Member")); | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
src/main/java/com/prgrms/catchtable/jwt/service/RefreshTokenService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.prgrms.catchtable.jwt.service; | ||
|
||
import com.prgrms.catchtable.jwt.domain.RefreshToken; | ||
import com.prgrms.catchtable.jwt.repository.RefreshTokenRepository; | ||
import com.prgrms.catchtable.jwt.token.Token; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.core.userdetails.UsernameNotFoundException; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class RefreshTokenService { | ||
|
||
private final RefreshTokenRepository refreshTokenRepository; | ||
|
||
@Transactional | ||
public void saveRefreshToken(Token totalToken) { | ||
String email = totalToken.getEmail(); | ||
|
||
if (refreshTokenRepository.existsRefreshTokenByEmail(email)) { | ||
refreshTokenRepository.deleteRefreshTokenByEmail(email); | ||
} | ||
|
||
RefreshToken newRefreshToken = RefreshToken.builder() | ||
.token(totalToken.getRefreshToken()) | ||
.email(email) | ||
.build(); | ||
|
||
refreshTokenRepository.save(newRefreshToken); | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public RefreshToken getRefreshTokenByToken(String refreshToken) { | ||
return refreshTokenRepository.findRefreshTokenByToken(refreshToken) | ||
.orElseThrow(() -> new UsernameNotFoundException("Not Found RefreshToken")); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.prgrms.catchtable.jwt.token; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
public class Token { | ||
|
||
private String accessToken; | ||
|
||
private String refreshToken; | ||
|
||
private String email; | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Security 필터내에서 예외를 던지면 이 예외가 인식이 되나요??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
예외 필터를 따로 구현 후, 앞단에 두어 처리해야합니다..!! 추가 후 리뷰요청 날리겠습니다~!