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 MVC(인증)] 최승훈 미션 제출합니다. #105

Open
wants to merge 3 commits into
base: sseung3424
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
23 changes: 23 additions & 0 deletions src/main/java/roomescape/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package roomescape;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import roomescape.member.AuthenticationInterceptor;

@Configuration
public class WebConfig implements WebMvcConfigurer {

private final AuthenticationInterceptor authenticationInterceptor;

public WebConfig(AuthenticationInterceptor authenticationInterceptor) {
this.authenticationInterceptor = authenticationInterceptor;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor)
.addPathPatterns("/admin/**")
.excludePathPatterns("/login", "/register");
}
}
48 changes: 48 additions & 0 deletions src/main/java/roomescape/member/AuthenticationInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package roomescape.member;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class AuthenticationInterceptor implements HandlerInterceptor {

private final MemberService memberService;

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

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Debug: start");
String token = null;
if (request.getCookies() != null) {
for (jakarta.servlet.http.Cookie cookie : request.getCookies()) {
if ("token".equals(cookie.getName())) {
token = cookie.getValue();
break;
}
}
}

if (token == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401 Unauthorized
return false;
}

Member member = memberService.findMemberByToken(token);
if (member == null) {
throw new IllegalArgumentException("유효하지 않은 토큰이나 사용자입니다.");
}

System.out.println("Debug: Role = " + member.getRole());
if (!"ADMIN".equals(member.getRole())) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}

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

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;

@Component
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(Member.class);
}

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
jakarta.servlet.http.HttpServletRequest request = webRequest.getNativeRequest(jakarta.servlet.http.HttpServletRequest.class);
if(request == null) {
throw new IllegalArgumentException("요청이 유효하지 않습니다.");
}
jakarta.servlet.http.Cookie[] cookies = request.getCookies();
if(cookies == null) {
throw new IllegalArgumentException("유효한 쿠키를 찾을 수 없습니다.");
}

String token = null;
for (jakarta.servlet.http.Cookie cookie : cookies) {
if ("token".equals(cookie.getName())) {
token = cookie.getValue();
break;
}
}
if(token == null) {
throw new IllegalArgumentException("유효한 토큰을 찾을 수 없습니다.");
}

Member member = memberService.findMemberByToken(token);
if (member == null) {
throw new IllegalArgumentException("유효하지 않은 토큰 또는 사용자입니다.");
}

return member;
}
}
32 changes: 32 additions & 0 deletions src/main/java/roomescape/member/MemberController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.UUID;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -25,6 +27,36 @@ public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) {
return ResponseEntity.created(URI.create("/members/" + member.getId())).body(member);
}

@PostMapping("/login")
public ResponseEntity login(@RequestBody MemberRequest memberRequest, HttpServletResponse response) {
if(memberService.findMember(memberRequest) != null) {
String token = memberService.createToken(memberRequest.getEmail(), memberRequest.getPassword());
Cookie cookie = new Cookie("token", token);
cookie.setPath("/");
cookie.setMaxAge(3600);
response.addCookie(cookie);
return ResponseEntity.ok().build();
}
return ResponseEntity.notFound().build();
}

@GetMapping("/login/check")
public ResponseEntity checkLogin(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if(cookies != null) {
for (Cookie cookie : cookies) {
if(cookie.getName().equals("token")) {
String token = cookie.getValue();
String name = memberService.findMemberByToken(token).getName();

return ResponseEntity.ok(Map.of("name", name));
}
}
}
return ResponseEntity.status(401).build();
}


@PostMapping("/logout")
public ResponseEntity logout(HttpServletResponse response) {
Cookie cookie = new Cookie("token", "");
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/roomescape/member/MemberService.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package roomescape.member;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.security.Key;
import java.util.Date;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.stereotype.Service;

@Service
Expand All @@ -14,4 +20,37 @@ public MemberResponse createMember(MemberRequest memberRequest) {
Member member = memberDao.save(new Member(memberRequest.getName(), memberRequest.getEmail(), memberRequest.getPassword(), "USER"));
return new MemberResponse(member.getId(), member.getName(), member.getEmail());
}

public MemberResponse findMember(MemberRequest memberRequest) {
Member member = memberDao.findByEmailAndPassword(memberRequest.getEmail(), memberRequest.getPassword());
return new MemberResponse(member.getId(), member.getName(), member.getEmail());
}

public String createToken(String email, String password) {
String secret = "roomescape-application-secret-key-for-login!";
Key key = new SecretKeySpec(secret.getBytes(), SignatureAlgorithm.HS256.getJcaName());
Member member = memberDao.findByEmailAndPassword(email, password);
return Jwts.builder()
.setSubject("user-identifier")
.claim("name", member.getName())
.claim("role", member.getRole())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000))
.signWith(key, SignatureAlgorithm.HS256)
.compact();
}

public Member findMemberByToken(String token) {
String secret = "roomescape-application-secret-key-for-login!";
Key key = new SecretKeySpec(secret.getBytes(), SignatureAlgorithm.HS256.getJcaName());

Claims claims = Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();

String name = claims.get("name", String.class);
return memberDao.findByName(name);
}
}
34 changes: 30 additions & 4 deletions src/main/java/roomescape/reservation/ReservationController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package roomescape.reservation;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.coyote.Response;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -10,14 +14,18 @@

import java.net.URI;
import java.util.List;
import roomescape.member.MemberService;

@RestController
public class ReservationController {

private final ReservationService reservationService;
private final MemberService memberService;

public ReservationController(ReservationService reservationService) {
public ReservationController(ReservationService reservationService,
final MemberService memberService) {
this.reservationService = reservationService;
this.memberService = memberService;
}

@GetMapping("/reservations")
Expand All @@ -26,13 +34,31 @@ public List<ReservationResponse> list() {
}

@PostMapping("/reservations")
public ResponseEntity create(@RequestBody ReservationRequest reservationRequest) {
if (reservationRequest.getName() == null
|| reservationRequest.getDate() == null
public ResponseEntity create(@RequestBody ReservationRequest reservationRequest, HttpServletRequest request) {
if (reservationRequest.getDate() == null
|| reservationRequest.getTheme() == null
|| reservationRequest.getTime() == null) {
return ResponseEntity.badRequest().build();
}
else if(reservationRequest.getName() == null) {
Cookie[] cookies = request.getCookies();
if (cookies == null) {
return ResponseEntity.status(401).body("유효한 쿠키를 찾을 수 없습니다.");
}
for(Cookie cookie : cookies) {
if(cookie.getName().equals("token")) {
String token = cookie.getValue();
if (token == null) {
return ResponseEntity.status(401).body("인증 토큰을 찾을 수 없습니다.");
}
String name = memberService.findMemberByToken(token).getName();
if(name == null) {
return ResponseEntity.status(401).body("유효하지 않은 토큰입니다.");
}
reservationRequest.setName(name);
}
}
}
ReservationResponse reservation = reservationService.save(reservationRequest);

return ResponseEntity.created(URI.create("/reservations/" + reservation.getId())).body(reservation);
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/roomescape/reservation/ReservationRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ public class ReservationRequest {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

public String getDate() {
return date;
Expand Down
Loading