Skip to content

Commit

Permalink
Merge pull request #22 from KTB16Team/feature/19-auth
Browse files Browse the repository at this point in the history
Feature/19 auth
  • Loading branch information
mng990 authored Oct 22, 2024
2 parents 88e15a8 + 42d20b4 commit 20ff15a
Show file tree
Hide file tree
Showing 45 changed files with 449 additions and 317 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package aiin.backend.common.cors;
package aiin.backend.auth.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import aiin.backend.common.properties.properties.CorsProperties;
import aiin.backend.auth.properties.CorsProperties;
import lombok.RequiredArgsConstructor;

@Configuration
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package aiin.backend.common.properties;
package aiin.backend.auth.config;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import aiin.backend.common.properties.properties.CorsProperties;
import aiin.backend.common.properties.properties.JwtProperties;
import aiin.backend.common.properties.properties.SecurityProperties;
import aiin.backend.auth.properties.CorsProperties;
import aiin.backend.auth.properties.JwtProperties;
import aiin.backend.auth.properties.SecurityProperties;

@Configuration
@EnableConfigurationProperties(value = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package aiin.backend.common.security;

import aiin.backend.common.properties.properties.SecurityProperties;
import aiin.backend.common.security.filter.exceptionHandlingFilter.ExceptionHandlingFilter;
import aiin.backend.common.security.filter.jwtFilter.JwtAuthenticationFilter;
import aiin.backend.common.security.filter.jwtFilter.JwtTokenProvider;
import aiin.backend.common.security.filter.loginFilter.LoginFilter;
import aiin.backend.domains.member.service.MemberService;
package aiin.backend.auth.config;

import aiin.backend.auth.properties.SecurityProperties;
import aiin.backend.auth.security.exceptionHandlingFilter.ExceptionHandlingFilter;
import aiin.backend.auth.security.jwtFilter.JwtAuthenticationFilter;
import aiin.backend.auth.security.jwtFilter.JwtTokenProvider;
import aiin.backend.auth.security.loginFilter.LoginFilter;
import aiin.backend.member.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package aiin.backend.common.exception;
package aiin.backend.auth.exception;

import lombok.Getter;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package aiin.backend.common.exception;
package aiin.backend.auth.exception;

import org.springframework.http.HttpStatus;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package aiin.backend.common.properties.properties;
package aiin.backend.auth.properties;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package aiin.backend.common.properties.properties;
package aiin.backend.auth.properties;

import lombok.Getter;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package aiin.backend.common.properties.properties;
package aiin.backend.auth.properties;

import lombok.Getter;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package aiin.backend.common.security.filter.exceptionHandlingFilter;
package aiin.backend.auth.security.exceptionHandlingFilter;

import aiin.backend.common.dto.ErrorResponse;
import aiin.backend.common.exception.ApiException;
import aiin.backend.common.exception.ErrorCode;
import aiin.backend.common.util.responseWriter.ResponseWriter;
import aiin.backend.util.dto.ErrorResponse;
import aiin.backend.auth.exception.ApiException;
import aiin.backend.auth.exception.ErrorCode;
import aiin.backend.util.responseWriter.ResponseWriter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package aiin.backend.common.security.filter.jwtFilter;
package aiin.backend.auth.security.jwtFilter;

import static aiin.backend.common.exception.ErrorCode.*;
import static aiin.backend.auth.exception.ErrorCode.*;

import aiin.backend.common.exception.ApiException;
import aiin.backend.common.exception.ErrorCode;
import aiin.backend.common.properties.properties.SecurityProperties;
import aiin.backend.auth.exception.ApiException;
import aiin.backend.auth.exception.ErrorCode;
import aiin.backend.auth.properties.SecurityProperties;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -56,7 +56,7 @@ protected void doFilterInternal(
//5. 그 외 모든 경우는 에러 리턴
if (refreshToken != null && jwtTokenProvider.isTokenValid(refreshToken)) {
log.info("refresh토큰 인증 성공");
jwtTokenProvider.checkRefreshTokenAndReIssueAccessAndRefreshToken(response, refreshToken);
jwtTokenProvider.checkRefreshTokenAndReIssueAccessAndRefreshToken(response, accessToken, refreshToken);
} else if (refreshToken != null && !jwtTokenProvider.isTokenValid(refreshToken)) {
log.info("refresh토큰 인증 실패");
throw ApiException.from(INVALID_REFRESH_TOKEN);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package aiin.backend.common.security.filter.jwtFilter;
package aiin.backend.auth.security.jwtFilter;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package aiin.backend.common.security.filter.jwtFilter;
package aiin.backend.auth.security.jwtFilter;

import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

Expand All @@ -13,11 +14,7 @@ public interface JwtTokenProvider {

String createAccessToken(Long memberId);

String createRefreshToken();

void updateRefreshToken(Long memberId, String refreshToken);

void destroyRefreshToken(Long memberId);
String createRefreshToken(Long memberId);

void sendAccessAndRefreshToken(HttpServletResponse response, String accessToken, String refreshToken);

Expand All @@ -37,7 +34,9 @@ public interface JwtTokenProvider {

boolean isTokenValid(String token);

void checkRefreshTokenAndReIssueAccessAndRefreshToken(HttpServletResponse response, String refreshToken);
void expireRefreshToken(Long memberId, String accessToken, String refreshToken);

void checkRefreshTokenAndReIssueAccessAndRefreshToken(HttpServletResponse response, String accessToken, String refreshToken);

boolean isLogout(String accessToken);
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package aiin.backend.common.security.filter.jwtFilter;

import static aiin.backend.common.exception.ErrorCode.*;

import aiin.backend.common.dto.DataResponse;
import aiin.backend.common.exception.ApiException;
import aiin.backend.common.properties.properties.JwtProperties;
import aiin.backend.common.security.filter.jwtFilter.JwtDTO.AccessAndRefreshTokenResponse;
import aiin.backend.common.security.filter.jwtFilter.JwtDTO.AccessTokenResponse;
import aiin.backend.common.util.responseWriter.ResponseWriter;
import aiin.backend.domains.member.domain.Member;
import aiin.backend.domains.member.domain.RefreshToken;
import aiin.backend.domains.member.repository.MemberRepository;
import aiin.backend.domains.member.service.LogoutService;
import aiin.backend.domains.member.service.RefreshTokenService;
package aiin.backend.auth.security.jwtFilter;

import static aiin.backend.auth.exception.ErrorCode.*;

import aiin.backend.util.dto.DataResponse;
import aiin.backend.auth.exception.ApiException;
import aiin.backend.auth.properties.JwtProperties;
import aiin.backend.util.responseWriter.ResponseWriter;
import aiin.backend.member.entity.Member;
import aiin.backend.member.entity.RefreshToken;
import aiin.backend.member.repository.MemberRepository;
import aiin.backend.member.service.LogoutService;
import aiin.backend.member.service.RefreshTokenService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
Expand Down Expand Up @@ -70,9 +68,9 @@ public Authentication getAuthentication(String accessToken) {
.orElseThrow(() -> ApiException.from(MEMBER_NOT_FOUND));

String email = member.getEmail();
String pw = member.getPw();
String pw = member.getPassword();

List<GrantedAuthority> authorities = List.of(new SimpleGrantedAuthority(member.getMemberRole().getValue()));
List<GrantedAuthority> authorities = List.of(new SimpleGrantedAuthority(member.getRole().getValue()));

return UsernamePasswordAuthenticationToken.authenticated(email, pw, authorities);
}
Expand All @@ -88,43 +86,29 @@ public String createAccessToken(Long memberId) {
}

@Override
public String createRefreshToken() {
public String createRefreshToken(Long memberId) {
return Jwts.builder()
.setSubject(jwtProperties.getREFRESH_TOKEN_SUBJECT())
.claim(jwtProperties.getMEMBER_ID_CLAIM(), memberId)
.setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getRefresh().getExpiration() * 1000L))
.signWith(key, SignatureAlgorithm.HS256)
.compact();
}

@Override
@Transactional
public void updateRefreshToken(Long memberId, String refreshToken) {
Optional<RefreshToken> optionalRefreshToken = refreshTokenService.findByMemberId(memberId);

// refreshToken이 없으면 생성 및 저장, 있으면 refreshToken 값 변경
RefreshToken refreshTokenObj;
if (optionalRefreshToken.isEmpty()) {
refreshTokenObj = new RefreshToken(refreshToken, memberId);
} else {
refreshTokenObj = optionalRefreshToken.get();
refreshTokenObj.setToken(refreshToken);
}

refreshTokenService.save(refreshTokenObj);
}

@Override
@Transactional
public void destroyRefreshToken(Long memberId) {
refreshTokenService.deleteByMemberId(memberId);
public void expireRefreshToken(Long memberId, String accessToken, String refreshToken) {
// refreshToken을 Black List에 저장
RefreshToken expiredRefreshToken = new RefreshToken(accessToken, refreshToken);
refreshTokenService.save(expiredRefreshToken);
}

@Override
public void sendAccessAndRefreshToken(HttpServletResponse response, String accessToken, String refreshToken) {
setAccessTokenHeader(response, accessToken);
setRefreshTokenHeader(response, refreshToken);

AccessAndRefreshTokenResponse accessAndRefreshTokenResponse = AccessAndRefreshTokenResponse.from(accessToken,
JwtDTO.AccessAndRefreshTokenResponse accessAndRefreshTokenResponse = JwtDTO.AccessAndRefreshTokenResponse.from(accessToken,
refreshToken);

ResponseWriter.writeResponse(response, DataResponse.from(accessAndRefreshTokenResponse), HttpStatus.OK);
Expand All @@ -134,7 +118,7 @@ public void sendAccessAndRefreshToken(HttpServletResponse response, String acces
public void sendAccessToken(HttpServletResponse response, String accessToken) {
setAccessTokenHeader(response, accessToken);

AccessTokenResponse accessTokenResponse = AccessTokenResponse.from(accessToken);
JwtDTO.AccessTokenResponse accessTokenResponse = JwtDTO.AccessTokenResponse.from(accessToken);

ResponseWriter.writeResponse(response, DataResponse.from(accessTokenResponse), HttpStatus.OK);
}
Expand Down Expand Up @@ -207,24 +191,26 @@ public boolean isTokenValid(String token) {
return false;
}

public void checkRefreshTokenAndReIssueAccessAndRefreshToken(HttpServletResponse response, String refreshToken) {
public void checkRefreshTokenAndReIssueAccessAndRefreshToken(HttpServletResponse response, String accessToken, String refreshToken) {
//refreshToken이 유효한지 확인
RefreshToken refreshTokenObj = refreshTokenService.findByToken(refreshToken)
.orElseThrow(() -> ApiException.from(INVALID_REFRESH_TOKEN));

Long memberId = refreshTokenObj.getMemberId();
Long memberId = extractMemberId(refreshToken)
.orElseThrow(() -> ApiException.from(INVALID_REFRESH_TOKEN));

String newAccessToken = createAccessToken(memberId);
String newRefreshToken = createRefreshToken();
if(refreshTokenService.existsByAccessToken(accessToken)){
throw ApiException.from(INVALID_REFRESH_TOKEN);
}

//기존 refreshToken 삭제 및 새로운 refreshToken 저장
updateRefreshToken(memberId, newRefreshToken);

String newAccessToken = createAccessToken(memberId);
String newRefreshToken = createRefreshToken(memberId);

expireRefreshToken(memberId, accessToken, refreshToken);
sendAccessAndRefreshToken(response, newAccessToken, newRefreshToken);
}

@Override
public boolean isLogout(String accessToken) {
return logoutService.existsByAccessToken(accessToken);
return !logoutService.existsByAccessToken(accessToken);
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package aiin.backend.common.security.filter.loginFilter;
package aiin.backend.auth.security.loginFilter;

import org.springframework.security.core.userdetails.User;
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;

import aiin.backend.domains.member.domain.Member;
import aiin.backend.domains.member.service.MemberService;
import aiin.backend.member.entity.Member;
import aiin.backend.member.service.MemberService;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
Expand All @@ -21,8 +21,8 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx
Member member = memberService.findByEmail(username)
.orElseThrow(() -> new UsernameNotFoundException("해당하는 회원을 찾을 수 없습니다."));

String pw = member.getPw();
String role = member.getMemberRole().getValue();
String pw = member.getPassword();
String role = member.getRole().getValue();

return User.builder()
.username(username)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package aiin.backend.common.security.filter.loginFilter;
package aiin.backend.auth.security.loginFilter;

import static aiin.backend.common.exception.ErrorCode.*;
import static aiin.backend.auth.exception.ErrorCode.*;

import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
Expand All @@ -10,12 +10,12 @@
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import aiin.backend.common.dto.DataResponse;
import aiin.backend.common.exception.ApiException;
import aiin.backend.common.security.filter.jwtFilter.JwtTokenProvider;
import aiin.backend.common.util.responseWriter.ResponseWriter;
import aiin.backend.domains.member.domain.Member;
import aiin.backend.domains.member.service.MemberService;
import aiin.backend.auth.security.jwtFilter.JwtTokenProvider;
import aiin.backend.util.dto.DataResponse;
import aiin.backend.auth.exception.ApiException;
import aiin.backend.util.responseWriter.ResponseWriter;
import aiin.backend.member.entity.Member;
import aiin.backend.member.service.MemberService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
Expand Down Expand Up @@ -66,10 +66,9 @@ protected void successfulAuthentication(
Long memberId = member.getId();

String accessToken = jwtTokenProvider.createAccessToken(memberId);
String refreshToken = jwtTokenProvider.createRefreshToken();
String refreshToken = jwtTokenProvider.createRefreshToken(memberId);

jwtTokenProvider.sendAccessAndRefreshToken(response, accessToken, refreshToken);
jwtTokenProvider.updateRefreshToken(memberId, refreshToken);

log.info("로그인 성공: {}", email);
log.info("accessToken={}", accessToken);
Expand Down
Loading

0 comments on commit 20ff15a

Please sign in to comment.