-
Notifications
You must be signed in to change notification settings - Fork 0
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
Feature/member security #20 #48
Changes from 10 commits
a7e8182
103168f
d0d888e
fb5ce75
3e51eeb
38e61e8
972f5b8
6fa84d8
7c7cf8c
eb2c401
b49ede3
9c2f173
587293f
945264c
c60b7c2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,8 +27,8 @@ dependencies { | |
implementation 'org.springframework.boot:spring-boot-starter-data-jpa' | ||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' | ||
implementation 'org.springframework.boot:spring-boot-starter-web' | ||
//implementation 'org.springframework.boot:spring-boot-starter-security' | ||
//implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6' | ||
implementation 'org.springframework.boot:spring-boot-starter-security' | ||
// implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6' | ||
// https://mvnrepository.com/artifact/io.github.cdimascio/dotenv-java | ||
implementation group: 'io.github.cdimascio', name: 'dotenv-java', version: '3.0.0' | ||
// https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui | ||
|
@@ -39,6 +39,13 @@ dependencies { | |
implementation 'com.sun.xml.bind:jaxb-core:2.3.0.1' | ||
implementation 'com.sun.xml.bind:jaxb-impl:2.3.3' | ||
|
||
// JSON Web Token (JWT) Core API | ||
implementation 'io.jsonwebtoken:jjwt-api:0.11.5' | ||
|
||
// Implementation and JSON support (runtime dependencies) | ||
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' | ||
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5' | ||
|
||
compileOnly 'org.projectlombok:lombok' | ||
developmentOnly 'org.springframework.boot:spring-boot-devtools' | ||
runtimeOnly 'com.mysql:mysql-connector-j' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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,77 @@ | ||
package com.seveneleven.devlens.domain.member.controller; | ||
|
||
import com.seveneleven.devlens.domain.member.dto.MemberJoinDto; | ||
import com.seveneleven.devlens.domain.member.dto.TokenDto; | ||
import com.seveneleven.devlens.domain.member.entity.Member; | ||
import com.seveneleven.devlens.domain.member.service.MemberService; | ||
import com.seveneleven.devlens.global.config.Annotation.AdminAuthorize; | ||
import com.seveneleven.devlens.global.config.Annotation.UserAuthorize; | ||
import com.seveneleven.devlens.global.config.JwtFilter; | ||
import com.seveneleven.devlens.global.config.TokenProvider; | ||
import lombok.AllArgsConstructor; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.util.ObjectUtils; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
@RestController | ||
@RequestMapping("/api") | ||
@AllArgsConstructor | ||
public class memberController { | ||
|
||
private final TokenProvider tokenProvider; | ||
private final AuthenticationManagerBuilder authenticationManagerBuilder; | ||
private final MemberService memberService; | ||
|
||
@PostMapping("/login") | ||
public ResponseEntity<?> login(MemberJoinDto dto) { | ||
HiSeungmin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Member member = memberService.getUserWithAuthorities(dto.getUserid()).get(); | ||
|
||
if (ObjectUtils.isEmpty(member)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if문의 조건식이 반대로 적용되어 있는 것 같습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 로그인 API 구현할 때 수정하도록 하겠습니다. |
||
|
||
UsernamePasswordAuthenticationToken authenticationToken = | ||
new UsernamePasswordAuthenticationToken(dto.getUserid(), dto.getPw()); | ||
|
||
// authenticate 메소드가 실행이 될 때 CustomUserDetailsService class의 loadUserByUsername 메소드가 실행 | ||
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); | ||
|
||
// authentication 객체를 createToken 메소드를 통해서 JWT Token을 생성 | ||
String jwt = tokenProvider.createToken(authentication); | ||
|
||
HttpHeaders httpHeaders = new HttpHeaders(); | ||
// response header에 jwt token에 넣어줌 | ||
httpHeaders.add(JwtFilter.AUTHORIZATION_HEADER, "Bearer " + jwt); | ||
|
||
// tokenDto를 이용해 response body에도 넣어서 리턴 | ||
return new ResponseEntity<>(new TokenDto(jwt), httpHeaders, HttpStatus.OK); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tokenDto(jwt)는 확인용으로 추가하신 것 같은데, 나중에 수정하실 땐 httpHeaders만 전달해도 될 것 같습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넵! 삭제 예정으로 주석 남겼습니다. |
||
} | ||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST); | ||
} | ||
HiSeungmin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
@PostMapping("/join") | ||
public ResponseEntity<String> join(@RequestBody MemberJoinDto dto) { | ||
try { | ||
// memberService.join(dto.getUserid(), dto.getPw()); | ||
return ResponseEntity.ok("join success"); | ||
} catch (Exception e) { | ||
return ResponseEntity.badRequest().body(e.getMessage()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 전체적으로 선언부와 반환타입은 컨벤션 기준으로 맞출 수 있다면 수정해주세요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. API 개발 시 반환타입 일괄 수정하겠습니다. |
||
} | ||
} | ||
|
||
@GetMapping("/setting/admin") | ||
@AdminAuthorize | ||
public String adminSettingPage() { | ||
return "admin_setting"; | ||
} | ||
|
||
@GetMapping("/setting/user") | ||
@UserAuthorize | ||
public String userSettingPage() { | ||
return "user_setting"; | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코드 패치에 대한 간단한 리뷰를 진행하겠습니다. 몇 가지 버그 위험 요소와 개선 사항을 제안합니다. 1.
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.seveneleven.devlens.domain.member.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.Size; | ||
import lombok.*; | ||
|
||
@Getter | ||
@Setter | ||
@Builder | ||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
public class MemberDto { | ||
|
||
@NotBlank | ||
@Size(min = 3, max = 50) | ||
private String username; | ||
|
||
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY) | ||
@NotBlank | ||
@Size(min = 3, max = 100) | ||
private String password; | ||
|
||
@NotBlank | ||
@Size(min = 3, max = 50) | ||
private String nickname; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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,12 @@ | ||
package com.seveneleven.devlens.domain.member.dto; | ||
|
||
import lombok.Getter; | ||
import lombok.Setter; | ||
|
||
@Getter | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코드 패치에 대한 간단한 코드 리뷰를 제공하겠습니다.
종합적으로, 주석을 보완하고, DTO의 비즈니스 로직에 맞는 필드를 정의하고, 보안적 요소를 고려하는 것이 필요합니다. 이 외에도 구현 방식에 따라 다를 수 있으니, 주변 코드와 명확하게 연관짓는 것이 중요합니다. |
||
@Setter | ||
public class MemberJoinDto { | ||
|
||
private String userid; | ||
private String pw; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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,11 @@ | ||
package com.seveneleven.devlens.domain.member.dto; | ||
|
||
import lombok.*; | ||
|
||
@Getter | ||
@Builder | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코드 패치에 대한 간단한 리뷰를 하겠습니다.
이 외에도 전체적인 코드 구조나 프로젝트의 특정 요구 사항에 따라 추가적인 검토가 필요할 수 있습니다. 코드 수정이 필요한 경우, 추가적인 정보와 함께 요청해 주시면 좋습니다. |
||
@AllArgsConstructor | ||
public class TokenDto { | ||
|
||
private final String token; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 값이 하나만 전달된다면 dto를 만들지 않아도 괜찮을 것 같습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네! 알겠습니다. |
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코드 패치를 검토해본 결과, 전반적으로 잘 작성된 코드입니다. 그러나 몇 가지 개선 사항과 버그 위험 요소를 제안드리겠습니다.
이러한 점들을 고려하여 코드를 조금 더 개선할 수 있을 것입니다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,21 @@ | ||
package com.seveneleven.devlens.domain.member.entity; | ||
|
||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
import com.seveneleven.devlens.domain.member.constant.MemberStatus; | ||
import com.seveneleven.devlens.domain.member.constant.Role; | ||
import com.seveneleven.devlens.domain.member.constant.YN; | ||
import com.seveneleven.devlens.global.entity.BaseEntity; | ||
import jakarta.persistence.*; | ||
import lombok.*; | ||
import org.springframework.security.crypto.password.PasswordEncoder; | ||
|
||
import java.time.LocalDate; | ||
import java.time.LocalDateTime; | ||
|
||
@Entity | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) | ||
@Table(name = "member") | ||
public class Member extends BaseEntity { | ||
|
||
|
@@ -21,7 +24,7 @@ public class Member extends BaseEntity { | |
@Column(name = "id") | ||
private Long id; // 회원 ID | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
@ManyToOne(fetch = FetchType.EAGER) | ||
@JoinColumn(name = "company_id", nullable = false, referencedColumnName = "id") | ||
private Company company; // 회사 ID (연관관계) | ||
|
||
|
@@ -40,7 +43,7 @@ public class Member extends BaseEntity { | |
|
||
@Column(name = "profile_image_exists", nullable = false) | ||
@Enumerated(EnumType.STRING) | ||
private YN profileImageExists; // 프로필 이미지 유무 | ||
private YN profileImageExists = YN.N; // 프로필 이미지 유무 | ||
|
||
@Column(name = "name", nullable = false, length = 100) | ||
private String name; // 이름 | ||
|
@@ -62,15 +65,15 @@ public class Member extends BaseEntity { | |
|
||
|
||
// 생성 메서드 | ||
public static Member createMember(String loginId, String password, Company companyId, Role role, String name, String email, | ||
LocalDate birthDate, String phoneNumber, Long departmentId, Long positionId) { | ||
public static Member createMember(String loginId, String password, Company company, Role role, String name, String email, | ||
LocalDate birthDate, String phoneNumber, Long departmentId, Long positionId, PasswordEncoder pwdEncoder) { | ||
Member member = new Member(); | ||
member.name = name; | ||
member.role = role; | ||
member.email = email; | ||
member.loginId = loginId; | ||
member.password = password; | ||
member.company = companyId; | ||
member.password = pwdEncoder.encode(password); | ||
member.company = company; | ||
member.birthDate = birthDate; | ||
member.phoneNumber = phoneNumber; | ||
member.positionId = positionId; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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,16 @@ | ||
package com.seveneleven.devlens.domain.member.repository; | ||
|
||
|
||
import com.seveneleven.devlens.domain.member.entity.Member; | ||
import org.springframework.data.jpa.repository.EntityGraph; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import java.util.Optional; | ||
|
||
public interface MemberRepository extends JpaRepository<Member, Long> { | ||
|
||
Optional<Member> findByLoginId(String loginId); | ||
|
||
@EntityGraph(attributePaths = {"role"}) | ||
Optional<Member> findOneWithAuthoritiesByLoginId(String loginId); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. role을 같이 확인하고 싶다면 Authentication을 활용해 보는 방법도 좋을 것 같습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Authentication 인증 객체에 대해 알아보고 적용해보겠습니다. |
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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,52 @@ | ||
package com.seveneleven.devlens.domain.member.service; | ||
|
||
import com.seveneleven.devlens.domain.member.entity.Member; | ||
import com.seveneleven.devlens.domain.member.repository.MemberRepository; | ||
import com.seveneleven.devlens.global.util.security.SecurityUtil; | ||
import jakarta.transaction.Transactional; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.security.crypto.password.PasswordEncoder; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.util.Optional; | ||
|
||
@Service | ||
public class MemberService { | ||
@Autowired | ||
PasswordEncoder passwordEncoder; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코드 패치에 대한 간단한 리뷰를 제공하겠습니다.
개선 사항을 반영하면 코드의 안정성과 가독성을 더욱 향상시킬 수 있습니다. 잘 진행되고 있는 것 같습니다! |
||
@Autowired | ||
MemberRepository repository; | ||
@Autowired | ||
MemberRepository memberRepository; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 혹시 MemberRepository를 두 번 작성하신 이유가 있나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 하나 삭제 하겠습니다👍 |
||
|
||
|
||
public Optional<Member> findOne(String loginId) { | ||
return repository.findByLoginId(loginId); | ||
} | ||
|
||
// public Long join(String userid, String pw) { | ||
// Optional<Company> companyOptional = companyRepository.findById(1L); | ||
// | ||
// Company company = companyOptional.orElseThrow(() -> | ||
// new IllegalStateException("Company with ID 1L not found") | ||
// ); | ||
// | ||
// Member member = Member.createMember(userid, pw, company, Role.USER, "박철수", "[email protected]", LocalDate.now(),"010-111-1111",1L,1L,passwordEncoder); | ||
// repository.save(member); | ||
// | ||
// return member.getId(); | ||
// } | ||
|
||
// 유저,권한 정보를 가져오는 메소드 | ||
@Transactional | ||
public Optional<Member> getUserWithAuthorities(String memberId) { | ||
return memberRepository.findOneWithAuthoritiesByLoginId(memberId); | ||
} | ||
|
||
// 현재 securityContext에 저장된 username의 정보만 가져오는 메소드 | ||
@Transactional | ||
public Optional<Member> getMyUserWithAuthorities() { | ||
return SecurityUtil.getCurrentUsername() | ||
.flatMap(memberRepository::findOneWithAuthoritiesByLoginId); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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,29 @@ | ||
package com.seveneleven.devlens.domain.member.service; | ||
|
||
import com.seveneleven.devlens.domain.member.entity.Member; | ||
import org.springframework.security.core.userdetails.User; | ||
import org.springframework.security.core.userdetails.UserDetails; | ||
import org.springframework.security.core.userdetails.UserDetailsService; | ||
import org.springframework.security.core.userdetails.UsernameNotFoundException; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
public class MyUserDetailsService implements UserDetailsService { | ||
private final MemberService memberService; | ||
|
||
public MyUserDetailsService(MemberService memberService) { | ||
this.memberService = memberService; | ||
} | ||
|
||
@Override | ||
public UserDetails loadUserByUsername(String insertedUserId){ | ||
HiSeungmin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Member member = memberService.findOne(insertedUserId) | ||
.orElseThrow(() -> new UsernameNotFoundException("User with ID '" + insertedUserId + "' not found.")); | ||
|
||
return User.builder() | ||
.username(member.getLoginId()) | ||
.password(member.getPassword()) | ||
.roles(member.getRole().toString()) | ||
.build(); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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,14 @@ | ||
package com.seveneleven.devlens.global.config.Annotation; | ||
|
||
import org.springframework.security.access.prepost.PreAuthorize; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Target({ ElementType.METHOD, ElementType.TYPE }) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@PreAuthorize("hasAnyRole('ADMIN')") | ||
public @interface AdminAuthorize { | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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,14 @@ | ||
package com.seveneleven.devlens.global.config.Annotation; | ||
|
||
import org.springframework.security.access.prepost.PreAuthorize; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Target({ ElementType.METHOD, ElementType.TYPE }) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@PreAuthorize("hasAnyRole('USER')") | ||
public @interface UserAuthorize { | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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,35 @@ | ||
package com.seveneleven.devlens.global.config; | ||
|
||
import com.seveneleven.devlens.global.response.ErrorCode; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import org.springframework.security.access.AccessDeniedException; | ||
import org.springframework.security.web.access.AccessDeniedHandler; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.io.IOException; | ||
|
||
/** | ||
* 인증된 사용자가 필요한 권한 없이 보호된 리소스에 접근하려고 할 때 처리하는 클래스 | ||
* | ||
* - Spring Security에서 권한 부족으로 인한 접근 거부 시 403 (Forbidden) 에러를 반환합니다. | ||
*/ | ||
@Component | ||
public class JwtAccessDeniedHandler implements AccessDeniedHandler { | ||
|
||
/** | ||
* 권한이 없는 사용자가 요청을 보낼 때 호출됩니다. | ||
* | ||
* @param request 클라이언트 요청 (HttpServletRequest) | ||
* @param response 서버 응답 (HttpServletResponse) | ||
* @param accessDeniedException 발생한 접근 거부 예외 (AccessDeniedException) | ||
* @throws IOException 입출력 예외 발생 시 | ||
*/ | ||
@Override | ||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) | ||
throws IOException { | ||
// 403 Forbidden 상태 코드 반환 | ||
response.sendError(ErrorCode.FORBIDDEN.getCode()); | ||
} | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코드 검토를 진행하겠습니다. 아래는 코드에 대한 피드백입니다:
이 수정 사항들이 반영되면 코드의 가독성과 안정성을 높일 수 있을 것으로 예상됩니다. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
코드 패치에 대한 간단한 리뷰를 아래에 제공합니다:
변수 추가에 대한 확인:
SPRING_JWT_TOKEN_VALIDITY
변수가 비밀 정도에 적합한지 검토해보세요. JWT 토큰의 유효성을 설정하는 값이라면, 보안적으로 중요한 정보일 수 있습니다. 이 값이 잘 보호되고 있는지 확인이 필요합니다.주석 추가: 새로운 환경 변수가 추가된 이유와 그 사용법에 대한 주석을 코드에 추가하면, 이후에 코드를 이해하는 데 도움이 될 것입니다.
테스트 체크: 이 변수를 사용하는 코드 또는 워크플로우가 제대로 동작하는지 테스트가 필요합니다. 특히 JWT 관련 코드에는 보안 결함이 발생할 수 있으므로, 유효 기간 설정이 올바르게 작동하는지 확인하세요.
베스트 프랙티스: 환경 변수는 정해진 형식으로 제공되는지 확인하고, 가능한 경우 데이터 형식 검사를 수행하여 유효성을 높이는 것이 좋은 방법입니다.
버전 관리: 만약 이 수정 사항이 중요한 변경이라면, 이를 설명하는 커밋 메시지를 추가하는 것이 좋습니다. 변경 사항에 대한 문서화는 협업에 큰 도움이 됩니다.
이 외에도 추가적인 코드 패턴이나 전체적인 구조와 관련된 개선점이 있을 수 있으니, 필요한 경우 심도 있는 코드 리뷰도 고려해보세요.