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 Data JPA] 김진주 미션 제출합니다. #60

Open
wants to merge 5 commits into
base: nova0128
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
6 changes: 4 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ 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-data-jpa'

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

Expand All @@ -26,9 +26,11 @@ dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:5.3.1'

testImplementation 'org.mockito:mockito-core:3.10.0'

runtimeOnly 'com.h2database:h2'
}

test {
useJUnitPlatform()
}
}
2 changes: 1 addition & 1 deletion src/main/java/roomescape/RoomescapeApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ public class RoomescapeApplication {
public static void main(String[] args) {
SpringApplication.run(RoomescapeApplication.class, args);
}
}
}
31 changes: 31 additions & 0 deletions src/main/java/roomescape/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package roomescape;

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.interceptor.AdminInterceptor;
import roomescape.login.LoginMemberArgumentResolver;
import roomescape.member.MemberService;

import java.util.List;

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

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

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

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

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import roomescape.member.MemberService;
import roomescape.member.ViewMemberResponse;

import java.security.Key;
import java.util.Arrays;

public class AdminInterceptor implements HandlerInterceptor {
private static final String SECRET_KEY = "Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=";
private static final Key KEY = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
private final MemberService memberService;

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

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Cookie[] cookies = request.getCookies();
if (cookies == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}

Cookie tokenCookie = Arrays.stream(cookies)
.filter(cookie -> "token".equals(cookie.getName()))
.findFirst()
.orElse(null);

if (tokenCookie == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}

try {
String token = tokenCookie.getValue();
Long memberId = Long.valueOf(Jwts.parserBuilder()
.setSigningKey(KEY)
.build()
.parseClaimsJws(token)
.getBody().getSubject());

ViewMemberResponse member = memberService.findMemberById(memberId);
if (member == null || !member.getRole().equals("ADMIN")) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}

return true;
}
}
31 changes: 31 additions & 0 deletions src/main/java/roomescape/login/LoginMember.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package roomescape.login;

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;
}
}
58 changes: 58 additions & 0 deletions src/main/java/roomescape/login/LoginMemberArgumentResolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package roomescape.login;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
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 jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import roomescape.login.LoginMember;
import roomescape.member.MemberService;
import roomescape.member.ViewMemberResponse;

import java.security.Key;

public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {
private static final String SECRET_KEY = "Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=";
private static final Key KEY = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
private final 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 request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("token")) {
String token = cookie.getValue();
Long memberId = Long.valueOf(Jwts.parserBuilder()
.setSigningKey(KEY)
.build()
.parseClaimsJws(token)
.getBody().getSubject());

ViewMemberResponse member = memberService.findMemberById(memberId);
if (member != null) {
return new LoginMember(member.getId(), member.getName(), member.getEmail(), member.getRole());
}
}
}
}
}
return null;
}
}
24 changes: 18 additions & 6 deletions src/main/java/roomescape/member/Member.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
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;

private String password;

private String role;

public Member(Long id, String name, String email, String role) {
Expand All @@ -13,31 +26,30 @@ public Member(Long id, String name, String email, String role) {
this.email = email;
this.role = role;
}

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

public Member() {

}

public Long getId() {
return id;
}

public String getName() {
return name;
}

public String getEmail() {
return email;
}

public String getPassword() {
return password;
}

public String getRole() {
return role;
}
}
}
75 changes: 69 additions & 6 deletions src/main/java/roomescape/member/MemberController.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package roomescape.member;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.security.Key;
import java.util.Map;

@RestController
public class MemberController {
private MemberService memberService;
private final MemberService memberService;
private static final String SECRET_KEY = "Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E=";
private static final Key KEY = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());

public MemberController(MemberService memberService) {
this.memberService = memberService;
Expand All @@ -25,8 +29,67 @@ public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) {
return ResponseEntity.created(URI.create("/members/" + member.getId())).body(member);
}

@PostMapping("/login")
public ResponseEntity<Void> login(@RequestBody Map<String, String> params, HttpServletResponse response) {
String email = params.get("email");
String password = params.get("password");

ViewMemberResponse viewMemberResponse = memberService.findMemberByEmailAndPassword(email, password);

if (viewMemberResponse != null) {
String token = Jwts.builder()
.setSubject(viewMemberResponse.getId().toString())
.claim("name", viewMemberResponse.getName())
.claim("role", viewMemberResponse.getRole())
.signWith(KEY)
.compact();

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

return ResponseEntity.ok().build();
}

return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}

@GetMapping("/login/check")
public ResponseEntity<MemberResponse> checkLogin(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
String token = extractTokenFromCookie(cookies);
if (!token.isEmpty()) {
try {
Long memberId = Long.valueOf(Jwts.parserBuilder()
.setSigningKey(KEY)
.build()
.parseClaimsJws(token)
.getBody().getSubject());

ViewMemberResponse viewMemberResponse = memberService.findMemberById(memberId);
MemberResponse memberResponse = new MemberResponse(viewMemberResponse.getId(), viewMemberResponse.getName(), viewMemberResponse.getEmail());
return ResponseEntity.ok(memberResponse);
} catch (Exception e) {
return ResponseEntity.status(401).build();
}
}
}
return ResponseEntity.status(401).build();
}

private String extractTokenFromCookie(Cookie[] cookies) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("token")) {
return cookie.getValue();
}
}
return "";
}

@PostMapping("/logout")
public ResponseEntity logout(HttpServletResponse response) {
public ResponseEntity<Void> logout(HttpServletResponse response) {
Cookie cookie = new Cookie("token", "");
cookie.setHttpOnly(true);
cookie.setPath("/");
Expand Down
Loading