Compare commits

..

4 Commits

Author SHA1 Message Date
dongHyo
e7fabb7c03 refactor: 생성자 메서드 위치 변경 2022-06-17 23:43:38 +09:00
dongHyo
7af5249116 feat: 계층권한 구현 2022-06-17 23:42:26 +09:00
Kim DongHyo
a235983475 refactor: 정적팩토리메서드 네이밍 통일 (#27) 2022-06-14 00:30:28 +09:00
Kim DongHyo
183e61188e Feature/redis set up and refresh token add (#24)
* feat: 로그인 시 refreshToken 추가 발행

* feat: redis 연결 및 refreshToken redis 저장

* refactor: Exception Class Naming 변경
2022-06-11 00:36:36 +09:00
10 changed files with 120 additions and 33 deletions

View File

@@ -0,0 +1,56 @@
package com.ticketing.server.global.security;
import com.ticketing.server.user.domain.UserGrade;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.annotation.Jsr250Voter;
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleHierarchyVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
@EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
@Configuration
public class RoleConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
expressionAdvice.setExpressionHandler(getExpressionHandler());
decisionVoters.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice));
decisionVoters.add(new Jsr250Voter());
decisionVoters.add(new RoleVoter());
decisionVoters.add(roleHierarchyVoter());
decisionVoters.add(new AuthenticatedVoter());
return new AffirmativeBased(decisionVoters);
}
@Bean
public RoleHierarchyVoter roleHierarchyVoter() {
return new RoleHierarchyVoter(roleHierarchy());
}
@Bean
public RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy(UserGrade.getRoleHierarchy());
return roleHierarchy;
}
}

View File

@@ -8,7 +8,6 @@ import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@@ -18,7 +17,6 @@ import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
@RequiredArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

View File

@@ -10,6 +10,7 @@ import com.ticketing.server.user.application.response.TokenDto;
import com.ticketing.server.user.application.response.UserChangePasswordResponse;
import com.ticketing.server.user.application.response.UserDeleteResponse;
import com.ticketing.server.user.domain.User;
import com.ticketing.server.user.domain.UserGrade;
import com.ticketing.server.user.service.UserServiceImpl;
import com.ticketing.server.user.service.interfaces.AuthenticationService;
import javax.servlet.http.HttpServletResponse;
@@ -32,7 +33,6 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RequestMapping("/api/user")
@Slf4j
public class UserController {
private final UserServiceImpl userService;
@@ -43,18 +43,18 @@ public class UserController {
@PostMapping
public ResponseEntity<SignUpResponse> register(@RequestBody @Valid SignUpRequest request) {
User user = userService.register(request.toSignUpDto(passwordEncoder));
return ResponseEntity.status(HttpStatus.CREATED).body(SignUpResponse.of(user));
return ResponseEntity.status(HttpStatus.CREATED).body(SignUpResponse.from(user));
}
@DeleteMapping
@Secured("ROLE_GUEST")
@Secured(UserGrade.ROLES.GUEST)
public ResponseEntity<UserDeleteResponse> deleteUser(@RequestBody @Valid UserDeleteRequest request) {
User user = userService.delete(request.toDeleteUserDto(passwordEncoder));
return ResponseEntity.status(HttpStatus.OK).body(UserDeleteResponse.of(user));
return ResponseEntity.status(HttpStatus.OK).body(UserDeleteResponse.from(user));
}
@PutMapping("/password")
@Secured("ROLE_GUEST")
@Secured(UserGrade.ROLES.GUEST)
public ResponseEntity<UserChangePasswordResponse> changePassword(@RequestBody @Valid UserModifyPasswordRequest request) {
if (request.oldEqualNew()) {
log.error("기존 패스워드와 동일한 패스워드로 변경할 수 없습니다.");
@@ -62,7 +62,7 @@ public class UserController {
}
User user = userService.changePassword(request.toChangePasswordDto(passwordEncoder));
return ResponseEntity.status(HttpStatus.OK).body(UserChangePasswordResponse.of(user));
return ResponseEntity.status(HttpStatus.OK).body(UserChangePasswordResponse.from(user));
}
@PostMapping("/login")

View File

@@ -13,7 +13,7 @@ public class SignUpResponse {
private String email;
public static SignUpResponse of(User user) {
public static SignUpResponse from(User user) {
return new SignUpResponse(user.getName(), user.getEmail());
}

View File

@@ -13,7 +13,7 @@ public class UserChangePasswordResponse {
private String email;
public static UserChangePasswordResponse of(User user) {
public static UserChangePasswordResponse from(User user) {
return new UserChangePasswordResponse(user.getName(), user.getEmail());
}

View File

@@ -13,7 +13,7 @@ public class UserDeleteResponse {
private String email;
public static UserDeleteResponse of(User user) {
public static UserDeleteResponse from(User user) {
return new UserDeleteResponse(user.getName(), user.getEmail());
}

View File

@@ -23,14 +23,6 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
public class User extends AbstractEntity {
public User(String name, String email, String password, UserGrade grade, String phone) {
this.name = name;
this.email = email;
this.password = password;
this.grade = grade;
this.phone = phone;
}
@Column(name = "name")
@NotEmpty(message = "{validation.not.empty.name}")
private String name;
@@ -58,6 +50,14 @@ public class User extends AbstractEntity {
private LocalDateTime deletedAt;
public User(String name, String email, String password, UserGrade grade, String phone) {
this.name = name;
this.email = email;
this.password = password;
this.grade = grade;
this.phone = phone;
}
public User delete(DeleteUserDTO deleteUser) {
if (isDeleted) {
throw new AlreadyDeletedException("이미 탈퇴된 회원 입니다.");

View File

@@ -1,5 +1,38 @@
package com.ticketing.server.user.domain;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public enum UserGrade {
GUEST, STAFF
ADMIN(ROLES.ADMIN, null),
STAFF(ROLES.STAFF, ROLES.ADMIN),
GUEST(ROLES.GUEST, ROLES.STAFF);
private final String roleName;
private final String parentName;
public static class ROLES {
public static final String ADMIN = "ROLE_ADMIN";
public static final String STAFF = "ROLE_STAFF";
public static final String GUEST = "ROLE_GUEST";
private ROLES() {
}
}
public static String getRoleHierarchy() {
StringBuilder sb = new StringBuilder();
for (UserGrade grade : UserGrade.values()) {
if (grade.parentName != null) {
sb.append(grade.parentName);
sb.append(" > ");
sb.append(grade.roleName);
sb.append("\n");
}
}
return sb.toString();
}
}

View File

@@ -6,13 +6,6 @@ import org.springframework.security.crypto.password.PasswordEncoder;
public class ChangePasswordDTO implements PasswordMatches {
public ChangePasswordDTO(String email, String oldPassword, String newPassword, PasswordEncoder passwordEncoder) {
this.email = email;
this.oldPassword = oldPassword;
this.newPassword = newPassword;
this.passwordEncoder = passwordEncoder;
}
@NotEmpty(message = "{validation.not.empty.email}")
@Email(message = "{validation.email}")
private String email;
@@ -25,6 +18,13 @@ public class ChangePasswordDTO implements PasswordMatches {
private PasswordEncoder passwordEncoder;
public ChangePasswordDTO(String email, String oldPassword, String newPassword, PasswordEncoder passwordEncoder) {
this.email = email;
this.oldPassword = oldPassword;
this.newPassword = newPassword;
this.passwordEncoder = passwordEncoder;
}
public String getEmail() {
return email;
}

View File

@@ -6,12 +6,6 @@ import org.springframework.security.crypto.password.PasswordEncoder;
public class DeleteUserDTO implements PasswordMatches {
public DeleteUserDTO(String email, String inputPassword, PasswordEncoder passwordEncoder) {
this.email = email;
this.inputPassword = inputPassword;
this.passwordEncoder = passwordEncoder;
}
@NotEmpty(message = "{validation.not.empty.email}")
@Email(message = "{validation.email}")
private String email;
@@ -21,6 +15,12 @@ public class DeleteUserDTO implements PasswordMatches {
private PasswordEncoder passwordEncoder;
public DeleteUserDTO(String email, String inputPassword, PasswordEncoder passwordEncoder) {
this.email = email;
this.inputPassword = inputPassword;
this.passwordEncoder = passwordEncoder;
}
@Override
public boolean passwordMatches(String password) {
return passwordEncoder.matches(this.inputPassword, password);