Compare commits
2 Commits
feature/ve
...
feature/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f85f06555 | ||
|
|
f037f4f46f |
@@ -9,7 +9,6 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
@@ -51,9 +50,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.antMatchers(HttpMethod.POST, "/api/user/login").permitAll()
|
||||
.antMatchers(HttpMethod.POST, "/api/user/refresh").permitAll()
|
||||
.antMatchers(HttpMethod.POST, "/api/user").permitAll()
|
||||
.antMatchers(HttpMethod.POST, "/api/auth/token").permitAll()
|
||||
.antMatchers(HttpMethod.POST, "/api/auth/refresh").permitAll()
|
||||
.antMatchers(HttpMethod.POST, "/api/users").permitAll()
|
||||
.antMatchers("/api/movies/**").permitAll()
|
||||
.antMatchers("/l7check").permitAll()
|
||||
.antMatchers("/actuator/**").permitAll()
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.ticketing.server.global.validator.constraints;
|
||||
|
||||
import com.ticketing.server.global.validator.constraintvalidators.FieldsValueNotMatchValidator;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
|
||||
@Constraint(validatedBy = FieldsValueNotMatchValidator.class)
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface FieldsValueNotMatch {
|
||||
|
||||
String message();
|
||||
|
||||
String field();
|
||||
|
||||
String fieldMatch();
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.ticketing.server.global.validator.constraintvalidators;
|
||||
|
||||
import com.ticketing.server.global.validator.constraints.FieldsValueNotMatch;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
|
||||
public class FieldsValueNotMatchValidator implements ConstraintValidator<FieldsValueNotMatch, Object> {
|
||||
|
||||
private String field;
|
||||
private String fieldMatch;
|
||||
|
||||
public void initialize(FieldsValueNotMatch constraintAnnotation) {
|
||||
this.field = constraintAnnotation.field();
|
||||
this.fieldMatch = constraintAnnotation.fieldMatch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Object value, ConstraintValidatorContext context) {
|
||||
Object fieldValue = new BeanWrapperImpl(value).getPropertyValue(field);
|
||||
Object fieldMatchValue = new BeanWrapperImpl(value).getPropertyValue(fieldMatch);
|
||||
|
||||
if (fieldValue != null) {
|
||||
return !fieldValue.equals(fieldMatchValue);
|
||||
} else {
|
||||
return fieldMatchValue != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.ticketing.server.user.application;
|
||||
|
||||
import com.ticketing.server.user.application.request.LoginRequest;
|
||||
import com.ticketing.server.user.application.response.TokenDto;
|
||||
import com.ticketing.server.user.service.interfaces.AuthenticationService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/auth")
|
||||
@Slf4j
|
||||
public class AuthController {
|
||||
|
||||
private final AuthenticationService authenticationService;
|
||||
|
||||
@PostMapping("/token")
|
||||
public ResponseEntity<TokenDto> login(@RequestBody LoginRequest loginRequest) {
|
||||
TokenDto tokenDto = authenticationService.generateTokenDto(loginRequest.toAuthentication());
|
||||
|
||||
return ResponseEntity.status(HttpStatus.OK)
|
||||
.headers(getHttpHeaders())
|
||||
.body(tokenDto);
|
||||
}
|
||||
|
||||
@PostMapping("/refresh")
|
||||
public ResponseEntity<TokenDto> refreshToken(@RequestParam("refreshToken") String refreshToken) {
|
||||
TokenDto tokenDto = authenticationService.reissueTokenDto(refreshToken);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.OK)
|
||||
.headers(getHttpHeaders())
|
||||
.body(tokenDto);
|
||||
}
|
||||
|
||||
private HttpHeaders getHttpHeaders() {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.set(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
|
||||
httpHeaders.set(HttpHeaders.PRAGMA, "no-store");
|
||||
httpHeaders.set(HttpHeaders.EXPIRES, "0");
|
||||
|
||||
return httpHeaders;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +1,15 @@
|
||||
package com.ticketing.server.user.application;
|
||||
|
||||
import com.ticketing.server.global.security.jwt.JwtProperties;
|
||||
import com.ticketing.server.user.application.request.LoginRequest;
|
||||
import com.ticketing.server.user.application.request.SignUpRequest;
|
||||
import com.ticketing.server.user.application.request.UserChangePasswordRequest;
|
||||
import com.ticketing.server.user.application.request.UserDeleteRequest;
|
||||
import com.ticketing.server.user.application.request.UserModifyPasswordRequest;
|
||||
import com.ticketing.server.user.application.response.SignUpResponse;
|
||||
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.application.response.UserDetailResponse;
|
||||
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;
|
||||
import javax.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -30,19 +25,16 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/user")
|
||||
@RequestMapping("/api/users")
|
||||
@Slf4j
|
||||
public class UserController {
|
||||
|
||||
private final UserServiceImpl userService;
|
||||
private final AuthenticationService authenticationService;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final JwtProperties jwtProperties;
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<SignUpResponse> register(@RequestBody @Valid SignUpRequest request) {
|
||||
@@ -50,9 +42,9 @@ public class UserController {
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(SignUpResponse.from(user));
|
||||
}
|
||||
|
||||
@GetMapping("/info")
|
||||
@GetMapping("/details")
|
||||
@Secured("ROLE_GUEST")
|
||||
public ResponseEntity<UserDetailResponse> myInfo(@AuthenticationPrincipal UserDetails userRequest) {
|
||||
public ResponseEntity<UserDetailResponse> details(@AuthenticationPrincipal UserDetails userRequest) {
|
||||
User user = userService.findByEmail(userRequest.getUsername());
|
||||
return ResponseEntity.status(HttpStatus.OK).body(UserDetailResponse.from(user));
|
||||
}
|
||||
@@ -66,32 +58,11 @@ public class UserController {
|
||||
|
||||
@PutMapping("/password")
|
||||
@Secured(UserGrade.ROLES.GUEST)
|
||||
public ResponseEntity<UserChangePasswordResponse> changePassword(@RequestBody @Valid UserModifyPasswordRequest request) {
|
||||
if (request.oldEqualNew()) {
|
||||
log.error("기존 패스워드와 동일한 패스워드로 변경할 수 없습니다.");
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
|
||||
}
|
||||
|
||||
User user = userService.changePassword(request.toChangePasswordDto(passwordEncoder));
|
||||
public ResponseEntity<UserChangePasswordResponse> changePassword(
|
||||
@AuthenticationPrincipal UserDetails userRequest,
|
||||
@RequestBody @Valid UserChangePasswordRequest request) {
|
||||
User user = userService.changePassword(request.toChangePasswordDto(userRequest.getUsername(), passwordEncoder));
|
||||
return ResponseEntity.status(HttpStatus.OK).body(UserChangePasswordResponse.from(user));
|
||||
}
|
||||
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<TokenDto> login(@RequestBody LoginRequest loginRequest, HttpServletResponse response) {
|
||||
TokenDto tokenDto = authenticationService.login(loginRequest.toAuthentication());
|
||||
|
||||
response.setHeader("Cache-Control", "no-store");
|
||||
response.setHeader("Pragma", "no-store");
|
||||
return ResponseEntity.status(HttpStatus.OK).body(tokenDto);
|
||||
}
|
||||
|
||||
@PostMapping("/refresh")
|
||||
public ResponseEntity<TokenDto> refreshToken(@RequestParam("refreshToken") String refreshToken, HttpServletResponse response) {
|
||||
TokenDto tokenDto = authenticationService.reissueAccessToken(refreshToken);
|
||||
|
||||
response.setHeader(jwtProperties.getAccessHeader(), tokenDto.getAccessToken());
|
||||
response.setHeader(jwtProperties.getRefreshHeader(), tokenDto.getRefreshToken());
|
||||
return ResponseEntity.status(HttpStatus.OK).body(tokenDto);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.ticketing.server.user.application.request;
|
||||
|
||||
import com.ticketing.server.global.validator.constraints.FieldsValueNotMatch;
|
||||
import com.ticketing.server.user.service.dto.ChangePasswordDTO;
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
@@ -11,11 +11,12 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserModifyPasswordRequest {
|
||||
|
||||
@NotEmpty(message = "{validation.not.empty.email}")
|
||||
@Email(message = "{validation.email}")
|
||||
private String email;
|
||||
@FieldsValueNotMatch(
|
||||
field = "oldPassword",
|
||||
fieldMatch = "newPassword",
|
||||
message = "{validation.password.not.change}"
|
||||
)
|
||||
public class UserChangePasswordRequest {
|
||||
|
||||
@NotEmpty(message = "{validation.not.empty.oldpassword}")
|
||||
private String oldPassword;
|
||||
@@ -23,12 +24,8 @@ public class UserModifyPasswordRequest {
|
||||
@NotEmpty(message = "{validation.not.empty.newpassword}")
|
||||
private String newPassword;
|
||||
|
||||
public ChangePasswordDTO toChangePasswordDto(PasswordEncoder passwordEncoder) {
|
||||
public ChangePasswordDTO toChangePasswordDto(String email, PasswordEncoder passwordEncoder) {
|
||||
return new ChangePasswordDTO(email, oldPassword, newPassword, passwordEncoder);
|
||||
}
|
||||
|
||||
public boolean oldEqualNew() {
|
||||
return oldPassword.equals(newPassword);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public TokenDto login(UsernamePasswordAuthenticationToken authenticationToken) {
|
||||
public TokenDto generateTokenDto(UsernamePasswordAuthenticationToken authenticationToken) {
|
||||
// 회원인증
|
||||
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
|
||||
|
||||
@@ -50,7 +50,7 @@ public class AuthenticationServiceImpl implements AuthenticationService {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public TokenDto reissueAccessToken(String bearerRefreshToken) {
|
||||
public TokenDto reissueTokenDto(String bearerRefreshToken) {
|
||||
String refreshToken = resolveToken(bearerRefreshToken);
|
||||
|
||||
// 토큰 검증
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.ticketing.server.global.security.service;
|
||||
package com.ticketing.server.user.service;
|
||||
|
||||
import com.ticketing.server.user.domain.User;
|
||||
import com.ticketing.server.user.domain.repository.UserRepository;
|
||||
@@ -5,8 +5,8 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
|
||||
|
||||
public interface AuthenticationService {
|
||||
|
||||
TokenDto login(UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken);
|
||||
TokenDto generateTokenDto(UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken);
|
||||
|
||||
TokenDto reissueAccessToken(String bearerRefreshToken);
|
||||
TokenDto reissueTokenDto(String bearerRefreshToken);
|
||||
|
||||
}
|
||||
|
||||
@@ -7,3 +7,4 @@ validation.not.empty.grade="\uC0AC\uC6A9\uC790 \uB4F1\uAE09\uC740 \uD544\uC218 \
|
||||
validation.not.empty.phone="\uD734\uB300\uBC88\uD638\uB294 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||
validation.email="\uC774\uBA54\uC77C\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
|
||||
validation.phone="\uD734\uB300\uBC88\uD638\uAC00 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
|
||||
validation.password.not.change="\uB3D9\uC77C\uD55C \uD328\uC2A4\uC6CC\uB4DC\uB85C \uBCC0\uACBD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
|
||||
|
||||
@@ -7,3 +7,4 @@ validation.not.empty.grade="user grade is required."
|
||||
validation.not.empty.phone="phone is required."
|
||||
validation.email="email is not valid."
|
||||
validation.phone="phone is not valid."
|
||||
validation.password.not.change="password not change."
|
||||
|
||||
@@ -7,3 +7,4 @@ validation.not.empty.grade="\uC0AC\uC6A9\uC790 \uB4F1\uAE09\uC740 \uD544\uC218 \
|
||||
validation.not.empty.phone="\uD734\uB300\uBC88\uD638\uB294 \uD544\uC218 \uC785\uB2C8\uB2E4."
|
||||
validation.email="\uC774\uBA54\uC77C\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
|
||||
validation.phone="\uD734\uB300\uBC88\uD638\uAC00 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
|
||||
validation.password.not.change="\uB3D9\uC77C\uD55C \uD328\uC2A4\uC6CC\uB4DC\uB85C \uBCC0\uACBD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
|
||||
|
||||
@@ -27,7 +27,10 @@ import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
@SpringBootTest
|
||||
@Transactional
|
||||
class UserControllerTest {
|
||||
class AuthControllerTest {
|
||||
|
||||
private static final String LOGIN_URL = "/api/auth/token";
|
||||
private static final String REGISTER_URL = "/api/users";
|
||||
|
||||
@Autowired
|
||||
WebApplicationContext context;
|
||||
@@ -53,7 +56,7 @@ class UserControllerTest {
|
||||
LoginRequest request = new LoginRequest("ticketing@gmail.com", "qwe123");
|
||||
|
||||
// when
|
||||
ResultActions actions = mvc.perform(post("/api/user/login")
|
||||
ResultActions actions = mvc.perform(post(LOGIN_URL)
|
||||
.content(asJsonString(request))
|
||||
.contentType(MediaType.APPLICATION_JSON));
|
||||
|
||||
@@ -69,7 +72,7 @@ class UserControllerTest {
|
||||
LoginRequest request = new LoginRequest("ticketing@gmail.com", "qwe1234");
|
||||
|
||||
// when
|
||||
ResultActions actions = mvc.perform(post("/api/user/login")
|
||||
ResultActions actions = mvc.perform(post(LOGIN_URL)
|
||||
.content(asJsonString(request))
|
||||
.contentType(MediaType.APPLICATION_JSON));
|
||||
|
||||
@@ -91,7 +94,7 @@ class UserControllerTest {
|
||||
|
||||
SignUpRequest signUpRequest = new SignUpRequest("ticketing", "ticketing@gmail.com", "qwe123", "010-2240-7920");
|
||||
|
||||
mvc.perform(post("/api/user")
|
||||
mvc.perform(post(REGISTER_URL)
|
||||
.content(asJsonString(signUpRequest))
|
||||
.contentType(MediaType.APPLICATION_JSON));
|
||||
}
|
||||
@@ -70,7 +70,7 @@ class AuthenticationServiceImplTest {
|
||||
when(jwtProperties.hasTokenStartsWith(refreshToken)).thenReturn(true);
|
||||
|
||||
// when
|
||||
TokenDto tokenDto = authenticationService.reissueAccessToken(refreshToken);
|
||||
TokenDto tokenDto = authenticationService.reissueTokenDto(refreshToken);
|
||||
|
||||
// then
|
||||
assertAll(
|
||||
|
||||
Reference in New Issue
Block a user