Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
// implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

implementation 'dev.akkinoc.spring.boot:logback-access-spring-boot-starter:4.0.0'

implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.2'
implementation 'io.jsonwebtoken:jjwt-gson:0.11.2'
implementation 'org.projectlombok:lombok:1.18.22'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:5.3.1'
Expand Down
5 changes: 5 additions & 0 deletions src/main/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## 8단계 요구사항
- [ ] DataLoader: 사용자 정보 초기화
- [ ] TestDataLoader: 테스트에 필요한 사전 값 초기화
- [ ] environment 분리

25 changes: 25 additions & 0 deletions src/main/java/roomescape/AdminInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package roomescape;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import roomescape.member.Member;
import roomescape.member.MemberService;

public class AdminInterceptor implements HandlerInterceptor {
private MemberService memberService;

public AdminInterceptor(MemberService memberService) {
this.memberService = memberService;
}

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
Member member = memberService.getMemberFromCookie(request);

if (member == null || !member.getRole().equals("ADMIN")) {
response.setStatus(401);
}
return true;
}
}
22 changes: 22 additions & 0 deletions src/main/java/roomescape/DataLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package roomescape;

import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import roomescape.member.Member;
import roomescape.member.MemberRepository;


public class DataLoader implements CommandLineRunner {

private MemberRepository memberRepository;

public DataLoader(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}

@Override
public void run(final String... args) throws Exception {
final Member member1 = memberRepository.save(new Member("어드민", "[email protected]", "password", "ADMIN"));
final Member member2 = memberRepository.save(new Member("브라운", "[email protected]", "password", "USER"));
}
}
14 changes: 14 additions & 0 deletions src/main/java/roomescape/Jwt/JwtConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package roomescape.Jwt;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import roomescape.Jwt.JwtUtils;

@Configuration
public class JwtConfig {

@Bean
public JwtUtils jwtUtils() {
return new JwtUtils();
}
}
29 changes: 29 additions & 0 deletions src/main/java/roomescape/Jwt/JwtUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package roomescape.Jwt;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import roomescape.member.Member;

public class JwtUtils {
@Value("${roomescape.auth.jwt.secret}") String secretKey;

public String createToken(Member member) {
String accessToken = Jwts.builder()
.setSubject(member.getId().toString())
.claim("name", member.getName())
.claim("role", member.getRole())
.signWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
.compact();
return accessToken;
}

public Long extractMemberId (String token) {
Long memberId = Long.valueOf(Jwts.parserBuilder()
.setSigningKey(Keys.hmacShaKeyFor(secretKey.getBytes()))
.build()
.parseClaimsJws(token)
.getBody().getSubject());
return memberId;
}
}
40 changes: 40 additions & 0 deletions src/main/java/roomescape/LoginMember.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package roomescape;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class LoginMember {
private Long id;
private String name;
private String email;
private String role;

public LoginMember(Long id, String name, String email, String role) {
this.id = id;
this.name = name;
this.email = email;
this.role = role;
}

public Long getId() {
return id;
}

public String getName() {
return name;
}

public String getEmail() {
return email;
}

public String getRole() {
return role;
}


}


35 changes: 35 additions & 0 deletions src/main/java/roomescape/LoginMemberArgumentResolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package roomescape;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import roomescape.member.Member;
import roomescape.member.MemberDao;
import roomescape.member.MemberService;

import java.util.Arrays;

public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {
private MemberService memberService;
public LoginMemberArgumentResolver(MemberService memberService) {
this.memberService = memberService;
}

@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(LoginMember.class);
}

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) webRequest.getNativeRequest();

Member member = memberService.getMemberFromCookie(httpServletRequest);

return new LoginMember(member.getId(), member.getName(), member.getEmail(), member.getRole());
}
}
49 changes: 49 additions & 0 deletions src/main/java/roomescape/TestDataLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package roomescape;

import org.springframework.boot.CommandLineRunner;
import roomescape.member.Member;
import roomescape.member.MemberRepository;
import roomescape.reservation.Reservation;
import roomescape.reservation.ReservationRepository;
import roomescape.theme.Theme;
import roomescape.theme.ThemeRepository;
import roomescape.time.Time;
import roomescape.time.TimeRepository;

public class TestDataLoader implements CommandLineRunner {

private MemberRepository memberRepository;
private ThemeRepository themeRepository;
private TimeRepository timeRepository;
private ReservationRepository reservationRepository;

public TestDataLoader(MemberRepository memberRepository, ThemeRepository themeRepository, TimeRepository timeRepository, ReservationRepository reservationRepository) {
this.memberRepository = memberRepository;
this.themeRepository = themeRepository;
this.timeRepository = timeRepository;
this.reservationRepository = reservationRepository;
}

@Override
public void run(String... args) throws Exception {
final Member member1 = memberRepository.save(new Member("어드민", "[email protected]", "password", "ADMIN"));
final Member member2 = memberRepository.save(new Member("브라운", "[email protected]", "password", "USER"));

final Theme theme1 = themeRepository.save(new Theme("테마1", "테마1입니다."));
final Theme theme2 = themeRepository.save(new Theme("테마2", "테마2입니다."));
final Theme theme3 = themeRepository.save(new Theme("테마3", "테마3입니다."));

final Time time1 = timeRepository.save(new Time("10:00"));
final Time time2 = timeRepository.save(new Time("12:00"));
final Time time3 = timeRepository.save(new Time("14:00"));
final Time time4 = timeRepository.save(new Time("16:00"));
final Time time5 = timeRepository.save(new Time("18:00"));
final Time time6 = timeRepository.save(new Time("20:00"));

final Reservation reservation1 = reservationRepository.save(new Reservation("어드민", "2024-03-01", time1, theme1));
final Reservation reservation2 = reservationRepository.save(new Reservation("어드민", "2024-03-01", time2, theme2));
final Reservation reservation3 = reservationRepository.save(new Reservation("어드민", "2024-03-01", time3, theme3));
final Reservation reservation4 = reservationRepository.save(new Reservation("브라운", "2024-03-01", time4, theme1));

}
}
28 changes: 28 additions & 0 deletions src/main/java/roomescape/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package roomescape;

import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import roomescape.member.MemberDao;
import roomescape.member.MemberService;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private MemberService memberService;

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new LoginMemberArgumentResolver(memberService));
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AdminInterceptor(memberService)).addPathPatterns("/admin/**");
}
}
47 changes: 47 additions & 0 deletions src/main/java/roomescape/auth/AuthController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package roomescape.auth;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import roomescape.member.MemberResponse;

@RestController
public class AuthController {
private final AuthService authService;

public AuthController(AuthService authService) {
this.authService = authService;
}

@PostMapping("/login")
public ResponseEntity<TokenResponse> login(@RequestBody TokenRequest tokenRequest, HttpServletResponse response) {
TokenResponse tokenResponse = authService.createToken(tokenRequest);

// cookie 생성
Cookie cookie = new Cookie("token", tokenResponse.getAccessToken());
cookie.setHttpOnly(true);
cookie.setPath("/");
response.addCookie(cookie);

return ResponseEntity.ok().body(tokenResponse);
}

@GetMapping("/login/check")
public ResponseEntity<MemberResponse> checkLogin(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
String token = extractTokenFromCookie(cookies);
MemberResponse memberResponse = authService.findMemberByToken(token);
return ResponseEntity.ok().body(memberResponse);
}

private String extractTokenFromCookie(Cookie[] cookies) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("token")){
return cookie.getValue();
}
}
return "";
}
}
47 changes: 47 additions & 0 deletions src/main/java/roomescape/auth/AuthService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package roomescape.auth;

import org.springframework.stereotype.Service;
import roomescape.Jwt.JwtUtils;
import roomescape.member.Member;
import roomescape.member.MemberDao;
import roomescape.member.MemberResponse;

@Service
public class AuthService {
private MemberDao memberDao;
// private TokenProvider tokenProvider;
// private AuthorizationExtractor authorizationExtractor;
private JwtUtils jwtUtils;

// public AuthService(MemberDao memberDao, TokenProvider tokenProvider, AuthorizationExtractor authorizationExtractor) {
// this.memberDao = memberDao;
// this.tokenProvider = tokenProvider;
// this.authorizationExtractor = authorizationExtractor;
// }
public AuthService(MemberDao memberDao, JwtUtils jwtUtils) {
this.memberDao = memberDao;
this.jwtUtils = jwtUtils;
}

public Member findMember(String email, String password) {
Member member = memberDao.findByEmailAndPassword(email, password);
if (member == null) {
throw new IllegalArgumentException();
}
return memberDao.findByEmailAndPassword(email, password);
}

public TokenResponse createToken(TokenRequest tokenRequest) {
Member member = findMember(tokenRequest.getEmail(), tokenRequest.getPassword());

String accessToken = jwtUtils.createToken(member);

return new TokenResponse(accessToken);
}

public MemberResponse findMemberByToken(String token) {
Long id = jwtUtils.extractMemberId(token);
Member member = memberDao.findById(id);
return new MemberResponse(member.getId(), member.getName(), member.getEmail());
}
}
23 changes: 23 additions & 0 deletions src/main/java/roomescape/auth/TokenRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package roomescape.auth;

public class TokenRequest {
private String email;
private String password;

public TokenRequest() {

}

public TokenRequest(String email, String password) {
this.email = email;
this.password = password;
}

public String getEmail() {
return email;
}

public String getPassword() {
return password;
}
}
Loading