Skip to content
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

[Spring Core] 윤성원 미션제출합니다. #72

Open
wants to merge 16 commits into
base: mete0rfish
Choose a base branch
from
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
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ 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'

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

import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import roomescape.member.Member;
import roomescape.member.MemberRepository;

@Profile("default")
@Component
public class DataLoader implements CommandLineRunner {

private MemberRepository memberRepository;

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

@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"
));
}
}
1 change: 1 addition & 0 deletions src/main/java/roomescape/RoomescapeApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;

@SpringBootApplication
public class RoomescapeApplication {
Expand Down
51 changes: 51 additions & 0 deletions src/main/java/roomescape/TestDataLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package roomescape;

import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
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;

@Profile("test")
@Component
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"));

reservationRepository.save(new Reservation("어드민", "2024-03-01", time1, theme1, member1));
reservationRepository.save(new Reservation("어드민", "2024-03-01", time2, theme2, member1));
reservationRepository.save(new Reservation("어드민", "2024-03-01", time3, theme3, member1));
reservationRepository.save(new Reservation("브라운", "2024-03-01", time4, theme1, member2));
}
}
15 changes: 15 additions & 0 deletions src/main/java/roomescape/api/JwtDecoder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package roomescape.api;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;

public class JwtDecoder {
public static Long decodeJwtToken(String token) {
Long memberId = Long.valueOf(Jwts.parserBuilder()
.setSigningKey(Keys.hmacShaKeyFor("Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=".getBytes()))
.build()
.parseClaimsJws(token)
.getBody().getSubject());
return memberId;
}
}
27 changes: 27 additions & 0 deletions src/main/java/roomescape/api/JwtUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package roomescape.api;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import roomescape.member.Member;

public class JwtUtils {

private String secretKey;

public JwtUtils() {

}

public JwtUtils(String secretKey) {
this.secretKey = secretKey;
}

public String createToken(Member member){
return Jwts.builder()
.setSubject(member.getId().toString())
.claim("name", member.getName())
.claim("role", member.getRole())
.signWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
.compact();
}
}
46 changes: 46 additions & 0 deletions src/main/java/roomescape/auth/AdminInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package roomescape.auth;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import roomescape.api.JwtDecoder;
import roomescape.exception.NotFoundException;
import roomescape.exception.UnauthorizedException;
import roomescape.member.Member;
import roomescape.member.MemberService;
import roomescape.util.CookieUtil;

@Component
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) throws Exception {
try {
String token = CookieUtil.extractTokenFromCookie(request.getCookies());
Long id = JwtDecoder.decodeJwtToken(token);
Member member = memberService.findById(id);

if (member == null) {
throw new NotFoundException("유저를 찾을 수 없습니다.");
} else if (!member.getRole().equals("ADMIN")) {
throw new UnauthorizedException("관리자 회원이 아닙니다.");
}

return true;
} catch (NotFoundException | UnauthorizedException e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write(e.getMessage());
return false;
} catch(Exception e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().write("예상치 못한 오류가 발생했습니다.");
return false;
}
}
}
17 changes: 17 additions & 0 deletions src/main/java/roomescape/auth/AuthConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package roomescape.auth;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import roomescape.api.JwtUtils;

@Configuration
public class AuthConfig {
@Bean
public JwtUtils jwtProvider(
@Value("${roomescape.auth.jwt.secret}")
String secretKey
) {
return new JwtUtils(secretKey);
}
}
22 changes: 22 additions & 0 deletions src/main/java/roomescape/auth/AuthService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package roomescape.auth;

import org.springframework.stereotype.Service;
import roomescape.api.JwtDecoder;
import roomescape.member.dto.LoginMember;
import roomescape.member.Member;
import roomescape.member.MemberService;

@Service
public class AuthService {
private MemberService memberService;

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

public LoginMember getLoginMemberWithToken(String token) {
Long id = JwtDecoder.decodeJwtToken(token);
Member member = memberService.findById(id);
return new LoginMember(member.getId(), member.getName(), member.getEmail(), member.getPassword());
}
}
22 changes: 22 additions & 0 deletions src/main/java/roomescape/config/InterceptorConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package roomescape.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import roomescape.auth.AdminInterceptor;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
private AdminInterceptor adminInterceptor;


public InterceptorConfig(AdminInterceptor adminInterceptor) {
this.adminInterceptor = adminInterceptor;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(adminInterceptor)
.addPathPatterns("/admin");
}
}
39 changes: 39 additions & 0 deletions src/main/java/roomescape/config/LoginMemberArgumentResolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package roomescape.config;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
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.api.JwtDecoder;
import roomescape.auth.AuthService;
import roomescape.member.Member;
import roomescape.util.CookieUtil;

@Component
public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {
private AuthService authService;

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

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

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
Cookie[] cookies = request.getCookies();
String token = CookieUtil.extractTokenFromCookie(cookies);
if(token == null){
return null;
}
return authService.getLoginMemberWithToken(token);
}
}
21 changes: 21 additions & 0 deletions src/main/java/roomescape/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package roomescape.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {
private final LoginMemberArgumentResolver loginMemberArgumentResolver;

public WebConfig(LoginMemberArgumentResolver loginMemberArgumentResolver) {
this.loginMemberArgumentResolver = loginMemberArgumentResolver;
}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(loginMemberArgumentResolver);
}
}
7 changes: 7 additions & 0 deletions src/main/java/roomescape/exception/NotFoundException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package roomescape.exception;

public class NotFoundException extends RuntimeException {
public NotFoundException(String message) {
super(message);
}
}
7 changes: 7 additions & 0 deletions src/main/java/roomescape/exception/UnauthorizedException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package roomescape.exception;

public class UnauthorizedException extends RuntimeException {
public UnauthorizedException(String message) {
super(message);
}
}
20 changes: 20 additions & 0 deletions src/main/java/roomescape/member/Member.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
package roomescape.member;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
Expand All @@ -21,6 +29,18 @@ public Member(String name, String email, String password, String role) {
this.role = role;
}

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

public Member() {

}

public Long getId() {
return id;
}
Expand Down
Loading