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
3 changes: 3 additions & 0 deletions be/issue-tracker-be/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ out/

### VS Code ###
.vscode/

### auth
auth.properties
3 changes: 3 additions & 0 deletions be/issue-tracker-be/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-hateoas'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.projectlombok:lombok:1.18.16'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
implementation 'org.projectlombok:lombok:1.18.16'

없애주세요

testImplementation 'org.springframework.boot:spring-boot-starter-test'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
compileOnly 'org.projectlombok:lombok'
Comment on lines 30 to 31
Copy link
Collaborator

Choose a reason for hiding this comment

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

여기에 의존성 등록 돼 있습니다~

runtimeOnly 'com.h2database:h2'
runtimeOnly 'mysql:mysql-connector-java'
implementation 'com.auth0:java-jwt:3.8.3'


implementation 'org.springdoc:springdoc-openapi-ui:1.5.8'
implementation 'org.springdoc:springdoc-openapi-data-rest:1.5.8'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.codesquad.issuetracker.auth.config;

import com.codesquad.issuetracker.auth.intercepter.LoginInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/auth/**");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.codesquad.issuetracker.auth.controller;

import com.codesquad.issuetracker.auth.dto.AuthResponse;
import com.codesquad.issuetracker.auth.dto.Type;
import com.codesquad.issuetracker.auth.service.AuthService;
import com.codesquad.issuetracker.auth.dto.GitHubAccessTokenResponse;
import com.codesquad.issuetracker.auth.util.JwtUtil;
import com.codesquad.issuetracker.user.UserDto;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.security.auth.message.AuthException;

@RequestMapping("/auth")
@Controller
public class AuthController {

private final AuthService authService;

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

//Fixme : front로 변경
@GetMapping("/callback")
public ResponseEntity<AuthResponse> callback(@RequestParam(value = "code") String code) throws AuthException {
return auth(code, "fe");
}

@GetMapping
public ResponseEntity<AuthResponse> auth(String code, String type) throws AuthException {
GitHubAccessTokenResponse token = authService.getAccessToken(code, type);
String accessToken = token.getAccessToken();

UserDto userDto = authService.getUserFromGitHub(accessToken);

ResponseEntity<AuthResponse> authResponseResponseEntity = ResponseEntity.status(HttpStatus.CREATED).
body(new AuthResponse(JwtUtil.createJwt(userDto)));

return authResponseResponseEntity;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.codesquad.issuetracker.auth.dto;

public class AuthRequest {
private String code;

public AuthRequest(String code) {
this.code = code;
}

public String getCode() {
return code;
}
}
Comment on lines +3 to +13
Copy link
Collaborator

Choose a reason for hiding this comment

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

이런 부분은 롬복으로 처리해도 충분하다고 봅니다

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.codesquad.issuetracker.auth.dto;

public class AuthResponse {
private final String token;

public AuthResponse(String token) {
this.token = token;
}

public String getToken() {
return token;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.codesquad.issuetracker.auth.dto;

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;

public class GitHubAccessTokenRequest {
@JsonProperty("client_id")
private final String clientId;

@JsonProperty("client_secret")
private final String clientSecret;

@JsonProperty("code")
private final String code;

public GitHubAccessTokenRequest(String clientId, String clientSecret, String code) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.code = code;
}

public String getClientId() {
return clientId;
}

public String getClientSecret() {
return clientSecret;
}

public String getCode() {
return code;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.codesquad.issuetracker.auth.dto;

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;

public class GitHubAccessTokenResponse {
@JsonProperty("access_token")
private String accessToken;

@JsonProperty("token_type")
private String tokenType;

@JsonProperty("scope")
private String scope;

public GitHubAccessTokenResponse() {
}

public GitHubAccessTokenResponse(String accessToken, String tokenType, String scope) {
this.accessToken = accessToken;
this.tokenType = tokenType;
this.scope = scope;
}

public String getScope() {
return scope;
}

public String getTokenType() {
return tokenType;
}

public String getAccessToken() {
return accessToken;
}

@JsonSetter("access_token")
Copy link
Collaborator

Choose a reason for hiding this comment

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

JsonProperty 있으면 필요없지 않나요?

public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}


@JsonSetter("token_type")
public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}



@JsonSetter("scope")
public void setScope(String scope) {
this.scope = scope;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.codesquad.issuetracker.auth.dto;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;

@PropertySource(value = "classpath:auth.properties")
public class GitHubOAuth {

@Value("${client_id}")
private static String clientId;

@Value("${client_secret}")
private static String clientSecret;

private static String code;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.codesquad.issuetracker.auth.dto;

public enum Type {
IOS("ios"),
FE("fe");

private final String type;

Type(String type) {
this.type = type;
}

public static boolean isFe(String type) {
return FE.type.equals(type);
}

public static boolean isIos(String type) {
return IOS.type.equals(type);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.codesquad.issuetracker.auth.exception;

public class AuthenticationException extends RuntimeException{
public AuthenticationException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.codesquad.issuetracker.auth.exception;

public class JWTCreationException extends RuntimeException{
public JWTCreationException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.codesquad.issuetracker.auth.exception;

public class JwtException extends RuntimeException {
public JwtException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.codesquad.issuetracker.auth.exception;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

// NOTE: Login이 필요한 API일 경우 사용
@Target({METHOD, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Documented
public @interface LoginRequired {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.codesquad.issuetracker.auth.intercepter;

import com.codesquad.issuetracker.auth.exception.LoginRequired;
import com.codesquad.issuetracker.auth.exception.AuthenticationException;
import com.codesquad.issuetracker.auth.util.JwtUtil;
import com.codesquad.issuetracker.user.UserDto;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import static org.springframework.http.HttpHeaders.AUTHORIZATION;

public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (isLoginRequired(handler)) {
authenticate(request);
}
return true;
}

private boolean isLoginRequired(Object handler) {
return handler instanceof HandlerMethod
Copy link
Collaborator

Choose a reason for hiding this comment

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

수정사항은 아니고 잘 몰라서 질문인데, instanceof는 안티 패턴이라고 알고 있어요. 핸들러 메소드가 아니면 예외 발생해야 하는거 아닌가요? 혹시 써야 하는 이유가 뭔가요?

&& ((HandlerMethod) handler).hasMethodAnnotation(LoginRequired.class);
}

private void authenticate(HttpServletRequest request) {
String[] splitAuth = request.getHeader(AUTHORIZATION).split(" ");
String tokenType = splitAuth[0].toLowerCase();
if (splitAuth.length < 1 || !tokenType.equals("bearer")) {
throw new AuthenticationException("잘못된 Authorization Header 입니다.");
}
UserDto userDto = JwtUtil.decodeJwt(splitAuth[1]);
Comment on lines +30 to +35
Copy link
Collaborator

Choose a reason for hiding this comment

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

유틸성 말고 객체로 처리할 수도 있겠네요

request.setAttribute("user", userDto);
}
}
Loading