-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from CodingWasabi/feature-3/auth
🌞[INIT] security 초기 세팅
- Loading branch information
Showing
18 changed files
with
478 additions
and
8 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
HELP.md | ||
.gradle | ||
.gradle/** | ||
build/ | ||
!gradle/wrapper/gradle-wrapper.jar | ||
!**/src/main/**/build/ | ||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
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
26 changes: 26 additions & 0 deletions
26
src/main/java/com/codingwasabi/trti/config/auth/jwt/JwtEntryPoint.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,26 @@ | ||
package com.codingwasabi.trti.config.auth.jwt; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.core.AuthenticationException; | ||
import org.springframework.security.web.AuthenticationEntryPoint; | ||
import org.springframework.stereotype.Component; | ||
|
||
import javax.servlet.ServletException; | ||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
import java.io.IOException; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class JwtEntryPoint implements AuthenticationEntryPoint { | ||
private final JwtProvider jwtProvider; | ||
|
||
@Override | ||
public void commence(HttpServletRequest request, | ||
HttpServletResponse response, | ||
AuthenticationException authException) throws IOException, ServletException { | ||
String exception = jwtProvider.setInvalidJwtMessage(jwtProvider.resolve(request)); | ||
// JWT 관련 인증 예외를 처리한다. 403 | ||
response.sendError(HttpServletResponse.SC_FORBIDDEN, exception); | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
src/main/java/com/codingwasabi/trti/config/auth/jwt/JwtFilter.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,30 @@ | ||
package com.codingwasabi.trti.config.auth.jwt; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
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; | ||
|
||
@RequiredArgsConstructor | ||
public class JwtFilter extends OncePerRequestFilter { | ||
private final JwtProvider jwtProvider; | ||
|
||
@Override | ||
protected void doFilterInternal(HttpServletRequest request, | ||
HttpServletResponse response, | ||
FilterChain filterChain) throws ServletException, IOException { | ||
String token = jwtProvider.resolve(request); | ||
// 토큰이 유효한 경우에는 인증정보를 추출한다. | ||
if(jwtProvider.validate(token)) { | ||
Authentication authentication = jwtProvider.getAuthentication(token); | ||
SecurityContextHolder.getContext().setAuthentication(authentication); | ||
} | ||
filterChain.doFilter(request, response); | ||
} | ||
} |
119 changes: 119 additions & 0 deletions
119
src/main/java/com/codingwasabi/trti/config/auth/jwt/JwtProvider.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,119 @@ | ||
package com.codingwasabi.trti.config.auth.jwt; | ||
|
||
import com.codingwasabi.trti.config.auth.security.MemberAdaptor; | ||
import io.jsonwebtoken.*; | ||
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.UserDetailsService; | ||
import org.springframework.stereotype.Component; | ||
|
||
import javax.annotation.PostConstruct; | ||
import javax.servlet.http.HttpServletRequest; | ||
import java.util.Base64; | ||
import java.util.Date; | ||
|
||
@Component | ||
public class JwtProvider { | ||
private final UserDetailsService securityService; | ||
private final Long validTimeMilli; | ||
private String key; | ||
|
||
public JwtProvider(@Value("${jwt.validTime}") Long validTime, | ||
@Value("${jwt.secret}") String key, | ||
UserDetailsService securityService) { | ||
this.securityService = securityService; | ||
this.validTimeMilli = validTime * 1000L; | ||
this.key = key; | ||
} | ||
|
||
@PostConstruct | ||
protected void init() { | ||
key = Base64.getEncoder().encodeToString(key.getBytes()); | ||
} | ||
|
||
/** | ||
* JWT 생성 | ||
* @param email | ||
* @return | ||
*/ | ||
public String create(String email, String providerId) { | ||
Date now = new Date(); | ||
Claims claims = Jwts.claims().setSubject(email); | ||
claims.put("providerId", providerId); | ||
return Jwts.builder() | ||
.setClaims(claims) | ||
.setIssuedAt(now) | ||
.setExpiration(new Date(now.getTime() + validTimeMilli)) | ||
.signWith(SignatureAlgorithm.HS256, key) | ||
.compact(); | ||
} | ||
|
||
|
||
/** | ||
* JWT 유효성 검증 (key 검증 및 만료일자 검증) | ||
* @param jwtToken | ||
* @return | ||
*/ | ||
public boolean validate(String jwtToken) { | ||
try { | ||
Jws<Claims> claimsJws = Jwts.parser() | ||
.setSigningKey(key) | ||
.parseClaimsJws(jwtToken); | ||
|
||
return claimsJws.getBody().getExpiration().before(new Date()); | ||
} catch (Exception e) { | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* JWT 에서 회원정보 추출 | ||
* @param jwtToken | ||
* @return | ||
*/ | ||
public Authentication getAuthentication(String jwtToken) { | ||
MemberAdaptor memberAdaptor = (MemberAdaptor) securityService | ||
.loadUserByUsername(getEmailFromToken(jwtToken)); | ||
|
||
return new UsernamePasswordAuthenticationToken(memberAdaptor, null, | ||
memberAdaptor.getAuthorities()); | ||
} | ||
|
||
/** | ||
* JWT 에서 email 추출 | ||
* @param jwtToken | ||
* @return | ||
*/ | ||
private String getEmailFromToken(String jwtToken) { | ||
return Jwts.parser() | ||
.setSigningKey(key) | ||
.parseClaimsJws(jwtToken) | ||
.getBody() | ||
.getSubject(); | ||
} | ||
|
||
/** | ||
* request 의 header 로부터 토큰 추출 | ||
* @param request | ||
* @return | ||
*/ | ||
public String resolve(HttpServletRequest request) { | ||
return request.getHeader("X-AUTH-TOKEN"); | ||
} | ||
|
||
public String setInvalidJwtMessage(String jwtToken) { | ||
try { | ||
Jwts.parser().setSigningKey(key).parseClaimsJws(jwtToken); | ||
return "Server 내부에서 발생한 인증 오류입니다. Concorn 개발팀에 문의하세요."; | ||
} catch (UnsupportedJwtException | MalformedJwtException e) { | ||
return "지원하지 않는 구성의 JWT 입니다. 버전 혹은 암호화 방식을 확인하세요."; | ||
} catch (ExpiredJwtException e) { | ||
return "만료된 JWT 입니다."; | ||
} catch (SignatureException e) { | ||
return "서버에서 허용하지 않은 key 로 생성한 JWT 입니다. 접근 거부"; | ||
} catch (IllegalArgumentException e) { | ||
return "JWT 가 공백 형태입니다. 헤더를 확인해주세요."; | ||
} | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
src/main/java/com/codingwasabi/trti/config/auth/oauth/kind/KakaoOauthInfo.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,68 @@ | ||
package com.codingwasabi.trti.config.auth.oauth.kind; | ||
|
||
import com.codingwasabi.trti.domain.member.model.entity.Member; | ||
import com.codingwasabi.trti.domain.member.model.enumValue.Gender; | ||
|
||
import java.util.Map; | ||
|
||
import static com.codingwasabi.trti.config.auth.oauth.provider.OauthProvider.KAKAO; | ||
|
||
public class KakaoOauthInfo implements OauthInfo{ | ||
private final Map<String, Object> attributeMap; | ||
|
||
private KakaoOauthInfo(Map<String, Object> attributeMap) { | ||
this.attributeMap = attributeMap; | ||
} | ||
|
||
public static KakaoOauthInfo from(Map<String, Object> attributeMap) { | ||
return new KakaoOauthInfo(attributeMap); | ||
} | ||
|
||
@Override | ||
public Gender getGender() { | ||
return (Gender) attributeMap.get("gender"); | ||
} | ||
|
||
@Override | ||
public String getAgeRange() { | ||
return (String) attributeMap.get("ageRange"); | ||
} | ||
|
||
@Override | ||
public String getImagePath() { | ||
return (String) attributeMap.get("profileImage"); | ||
} | ||
|
||
@Override | ||
public String getProviderId() { | ||
return "k_" + attributeMap.get("kakaoId"); | ||
} | ||
|
||
@Override | ||
public String getProviderKind() { | ||
return KAKAO.toString(); | ||
} | ||
|
||
@Override | ||
public String getEmail() { | ||
return (String) attributeMap.get("email"); | ||
} | ||
|
||
@Override | ||
public String getNickname() { | ||
return (String) attributeMap.get("nickname"); | ||
} | ||
|
||
@Override | ||
public Member getEntity() { | ||
return Member.builder() | ||
.oauthId(getProviderId()) | ||
.email(getEmail()) | ||
.ageRange(getAgeRange()) | ||
.gender(getGender()) | ||
.imagePath(getImagePath()) | ||
.nickname(getNickname()) | ||
.provider(KAKAO) | ||
.build(); | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/main/java/com/codingwasabi/trti/config/auth/oauth/kind/OauthInfo.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,22 @@ | ||
package com.codingwasabi.trti.config.auth.oauth.kind; | ||
|
||
import com.codingwasabi.trti.domain.member.model.entity.Member; | ||
import com.codingwasabi.trti.domain.member.model.enumValue.Gender; | ||
|
||
public interface OauthInfo { | ||
String getProviderId(); | ||
|
||
String getProviderKind(); | ||
|
||
String getEmail(); | ||
|
||
String getNickname(); | ||
|
||
Gender getGender(); | ||
|
||
String getAgeRange(); | ||
|
||
String getImagePath(); | ||
|
||
Member getEntity(); | ||
} |
5 changes: 5 additions & 0 deletions
5
src/main/java/com/codingwasabi/trti/config/auth/oauth/provider/OauthProvider.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,5 @@ | ||
package com.codingwasabi.trti.config.auth.oauth.provider; | ||
|
||
public enum OauthProvider { | ||
KAKAO; | ||
} |
29 changes: 29 additions & 0 deletions
29
src/main/java/com/codingwasabi/trti/config/auth/oauth/service/OauthService.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,29 @@ | ||
package com.codingwasabi.trti.config.auth.oauth.service; | ||
|
||
import com.codingwasabi.trti.config.auth.oauth.kind.KakaoOauthInfo; | ||
import com.codingwasabi.trti.config.auth.oauth.kind.OauthInfo; | ||
import com.codingwasabi.trti.config.auth.oauth.provider.OauthProvider; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.util.Map; | ||
|
||
@Service | ||
public class OauthService { | ||
public OauthInfo filtrateOauth(String provider, Map<String, Object> requestMap) { | ||
if(isKakao(provider)) { | ||
return getKakao(requestMap); | ||
} | ||
|
||
// error code 추가 | ||
// "올바르지 못한 oauth 접근" | ||
throw new IllegalArgumentException("Error"); | ||
} | ||
|
||
private OauthInfo getKakao(Map<String, Object> requestMap) { | ||
return KakaoOauthInfo.from(requestMap); | ||
} | ||
|
||
private boolean isKakao(String provider) { | ||
return provider.equals(OauthProvider.KAKAO); | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
src/main/java/com/codingwasabi/trti/config/auth/security/MemberAdaptor.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,57 @@ | ||
package com.codingwasabi.trti.config.auth.security; | ||
|
||
import com.codingwasabi.trti.domain.member.model.entity.Member; | ||
import lombok.Getter; | ||
import org.springframework.security.core.GrantedAuthority; | ||
import org.springframework.security.core.authority.SimpleGrantedAuthority; | ||
import org.springframework.security.core.userdetails.UserDetails; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
|
||
public class MemberAdaptor implements UserDetails { | ||
|
||
@Getter | ||
public final Member member; | ||
|
||
public MemberAdaptor(Member member) { | ||
this.member = member; | ||
} | ||
|
||
@Override | ||
public Collection<? extends GrantedAuthority> getAuthorities() { | ||
Collection<GrantedAuthority> authorities = new ArrayList<>(); | ||
authorities.add(new SimpleGrantedAuthority(member.getAuthority().getRole())); | ||
return authorities; | ||
} | ||
|
||
@Override | ||
public String getPassword() { | ||
return null; | ||
} | ||
|
||
@Override | ||
public String getUsername() { | ||
return member.getEmail(); | ||
} | ||
|
||
@Override | ||
public boolean isAccountNonExpired() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public boolean isAccountNonLocked() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public boolean isCredentialsNonExpired() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public boolean isEnabled() { | ||
return true; | ||
} | ||
} |
Oops, something went wrong.