Skip to content

[Sping MVC(인증)] 김예진 미션 제출합니다. #160

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

Open
wants to merge 5 commits into
base: dpwls0125
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
43 changes: 43 additions & 0 deletions src/main/java/roomescape/auth/AdminRoleCheckInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package roomescape.auth;

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

import java.util.Arrays;

@Component
public class AdminRoleCheckInterceptor implements HandlerInterceptor {
private final AuthService authService;

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

@Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws Exception {
Cookie[] cookies = request.getCookies();

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

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

LoginMember member = authService.parseMemberInfo(token);

if (member == null || !member.getRole().equals("ADMIN")) {
response.setStatus(401);
return false;
}
return true;
}

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


import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import roomescape.member.MemberResponse;
import roomescape.token.TokenResponse;

@Controller
public class AuthController {

private final AuthService authService;

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

@PostMapping("/logout")
public ResponseEntity logout(HttpServletResponse response) {
Cookie cookie = new Cookie("token", "");
cookie.setHttpOnly(true);
cookie.setPath("/");
cookie.setMaxAge(0);
response.addCookie(cookie);
return ResponseEntity.ok().build();
}

@GetMapping("/login/check")
public ResponseEntity<MemberResponse> loginCheck(LoginMember loginMember) {
if (loginMember == null) {
return ResponseEntity.status(401).build();
}
MemberResponse response = new MemberResponse(loginMember.getId(), loginMember.getName(), loginMember.getEmail());
return ResponseEntity.ok().body(response);
}

@PostMapping("/login")
public ResponseEntity<Void> login(@RequestBody LoginRequest loginRequest) {
TokenResponse token = authService.createToken(loginRequest.email(), loginRequest.password());
ResponseCookie cookie = ResponseCookie.from("token", token.getAccessToken())
.httpOnly(true)
.path("/")
.build();

return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, cookie.toString())
.build();
}
}
37 changes: 37 additions & 0 deletions src/main/java/roomescape/auth/AuthService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package roomescape.auth;

import org.springframework.stereotype.Service;
import roomescape.member.Member;
import roomescape.member.MemberDao;
import roomescape.token.TokenParser;
import roomescape.token.TokenProvider;
import roomescape.token.TokenResponse;

@Service
public class AuthService {
private final MemberDao memberDao;
private final TokenProvider tokenProvider;
private final TokenParser tokenParser;

public AuthService(MemberDao memberDao, TokenProvider tokenProvider, TokenParser tokenParser) {
this.memberDao = memberDao;
this.tokenProvider = tokenProvider;
this.tokenParser = tokenParser;
}

public TokenResponse createToken(String email, String password) {
Member member = memberDao.findByEmailAndPassword(email, password);
if (member == null) {
throw new IllegalArgumentException("등록 되지 않은 사용자입니다.");
}
String token = tokenProvider.createAccessToken(member);
return new TokenResponse(token);
}

public LoginMember parseMemberInfo(String token) {
if (token == null || token.isBlank()) {
throw new IllegalArgumentException("로그인 하지 않은 사용자입니다.");
}
return tokenParser.parseMemberInfo(token);
}
}
32 changes: 32 additions & 0 deletions src/main/java/roomescape/auth/LoginMember.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package roomescape.auth;

public class LoginMember {

private Long id;
private String name;
private String email;
private String role;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

role은 enum인 것이 더 관리되기 쉽지 않을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 User, Admin과 같이 허용 된 역할만 명시적으로 관리하고 잘못된 값이 들어가는 것을 방지하기 위해서 ENUM을 사용하는 것이 좋을 것 같습니다!


public LoginMember(final Long id, final String name, final String email, final 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;
}
}
27 changes: 27 additions & 0 deletions src/main/java/roomescape/auth/LoginMemberArgumentResolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package roomescape.auth;

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;

@Component
public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {

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

@Override
public Object resolveArgument(final MethodParameter parameter, final ModelAndViewContainer mavContainer, final NativeWebRequest webRequest, final WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
LoginMember loginMember = (LoginMember) request.getAttribute("loginMember");
return loginMember;
}


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

public record LoginRequest(String email, String password) {
}
39 changes: 39 additions & 0 deletions src/main/java/roomescape/auth/TokenInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package roomescape.auth;

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

import java.util.Arrays;

@Component
public class TokenInterceptor implements HandlerInterceptor {

private final AuthService authService;

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

@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;
}

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

LoginMember loginMember = authService.parseMemberInfo(token);
request.setAttribute("loginMember", loginMember);
return HandlerInterceptor.super.preHandle(request, response, handler);
}
}
49 changes: 49 additions & 0 deletions src/main/java/roomescape/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package roomescape.config;

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.auth.AdminRoleCheckInterceptor;
import roomescape.auth.LoginMemberArgumentResolver;
import roomescape.auth.TokenInterceptor;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {

private final LoginMemberArgumentResolver loginMemberArgumentResolver;
private final AdminRoleCheckInterceptor adminRoleCheckInterceptor;
private final TokenInterceptor tokenInterceptor;

public WebConfig(LoginMemberArgumentResolver loginMemberArgumentResolver, AdminRoleCheckInterceptor adminRoleCheckInterceptor, TokenInterceptor tokenInterceptor) {
this.loginMemberArgumentResolver = loginMemberArgumentResolver;
this.adminRoleCheckInterceptor = adminRoleCheckInterceptor;
this.tokenInterceptor = tokenInterceptor;
}

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

@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(adminRoleCheckInterceptor)
.addPathPatterns("/admin/**");

registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(
"/",
"/signup",
"/signup/**",
"/login",
"/logout",
"/error"
);


}
}
8 changes: 4 additions & 4 deletions src/main/java/roomescape/member/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ public class Member {
private String name;
private String email;
private String password;
private String role;
private Role role;

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

public Member(String name, String email, String password, String role) {
public Member(String name, String email, String password, Role role) {
this.name = name;
this.email = email;
this.password = password;
Expand All @@ -37,7 +37,7 @@ public String getPassword() {
return password;
}

public String getRole() {
public Role getRole() {
return role;
}
}
15 changes: 1 addition & 14 deletions src/main/java/roomescape/member/MemberController.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package roomescape.member;

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.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -22,16 +18,7 @@ public MemberController(MemberService memberService) {
@PostMapping("/members")
public ResponseEntity createMember(@RequestBody MemberRequest memberRequest) {
MemberResponse member = memberService.createMember(memberRequest);
return ResponseEntity.created(URI.create("/members/" + member.getId())).body(member);
return ResponseEntity.created(URI.create("/members/" + member.id())).body(member);
}

@PostMapping("/logout")
public ResponseEntity logout(HttpServletResponse response) {
Cookie cookie = new Cookie("token", "");
cookie.setHttpOnly(true);
cookie.setPath("/");
cookie.setMaxAge(0);
response.addCookie(cookie);
return ResponseEntity.ok().build();
}
}
8 changes: 4 additions & 4 deletions src/main/java/roomescape/member/MemberDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ public Member save(Member member) {
ps.setString(1, member.getName());
ps.setString(2, member.getEmail());
ps.setString(3, member.getPassword());
ps.setString(4, member.getRole());
ps.setString(4, member.getRole().name());
return ps;
}, keyHolder);

return new Member(keyHolder.getKey().longValue(), member.getName(), member.getEmail(), "USER");
return new Member(keyHolder.getKey().longValue(), member.getName(), member.getEmail(), member.getRole());
}

public Member findByEmailAndPassword(String email, String password) {
Expand All @@ -34,7 +34,7 @@ public Member findByEmailAndPassword(String email, String password) {
rs.getLong("id"),
rs.getString("name"),
rs.getString("email"),
rs.getString("role")
Role.valueOf(rs.getString("role"))
),
email, password
);
Expand All @@ -47,7 +47,7 @@ public Member findByName(String name) {
rs.getLong("id"),
rs.getString("name"),
rs.getString("email"),
rs.getString("role")
Role.valueOf(rs.getString("role"))
),
name
);
Expand Down
Loading