admin: 로그인 service 경로 분리

This commit is contained in:
geonhos 2024-05-21 12:01:27 +09:00
parent 1bc356e0a4
commit 618f92df7a
20 changed files with 115 additions and 176 deletions

View File

@ -1,4 +1,4 @@
package com.bpgroup.poc.admin.security.authentication.service; package com.bpgroup.poc.admin.app.authentication;
import lombok.Data; import lombok.Data;
@ -6,7 +6,7 @@ import lombok.Data;
* 로그인 요청 Request * 로그인 요청 Request
*/ */
@Data @Data
public class LoginRequest { public class AuthenticationRequest {
private String username; private String username;
private String password; private String password;
} }

View File

@ -0,0 +1,27 @@
package com.bpgroup.poc.admin.app.authentication;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
public class AuthenticationResponse {
private String resultCode;
private String resultMessage;
public static AuthenticationResponse success() {
AuthenticationResponse response = new AuthenticationResponse();
response.resultCode = "0000";
response.resultMessage = "Success";
return response;
}
public static AuthenticationResponse fail(String resultCode, String resultMessage) {
AuthenticationResponse response = new AuthenticationResponse();
response.resultCode = resultCode;
response.resultMessage = resultMessage;
return response;
}
}

View File

@ -0,0 +1,18 @@
package com.bpgroup.poc.admin.app.authentication;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class AuthenticationResult {
private final Long id;
private final String loginId;
private final String name;
private final String email;
public static AuthenticationResult of(Long id, String loginId, String name, String email) {
return new AuthenticationResult(id, loginId, name, email);
}
}

View File

@ -0,0 +1,36 @@
package com.bpgroup.poc.admin.app.authentication;
import com.bpgroup.poc.admin.app.authentication.exception.AdminNotFoundException;
import com.bpgroup.poc.admin.app.authentication.exception.DoNotHaveAnyMenuException;
import com.bpgroup.poc.admin.app.authentication.exception.InvalidPasswordException;
import com.bpgroup.poc.admin.domain.base.admin.entity.Admin;
import com.bpgroup.poc.admin.domain.base.admin.entity.AdminRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
public class AuthenticationService {
private final PasswordEncoder passwordEncoder;
private final AdminRepository adminRepository;
@Transactional
public AuthenticationResult login(String username, String password) throws AdminNotFoundException, InvalidPasswordException, DoNotHaveAnyMenuException {
Admin findAdmin = adminRepository.findByLoginId(username).orElseThrow(() -> new AdminNotFoundException(username));
if (!passwordEncoder.matches(password, findAdmin.getPassword())) {
throw new InvalidPasswordException(username);
}
return AuthenticationResult.of(
findAdmin.getId(),
findAdmin.getLoginId(),
findAdmin.getName(),
findAdmin.getLoginId()
);
}
}

View File

@ -1,4 +1,4 @@
package com.bpgroup.poc.admin.security.authentication.service.exception; package com.bpgroup.poc.admin.app.authentication.exception;
public class AdminNotFoundException extends Exception { public class AdminNotFoundException extends Exception {
public AdminNotFoundException(String message) { public AdminNotFoundException(String message) {

View File

@ -1,4 +1,4 @@
package com.bpgroup.poc.admin.security.authentication.service.exception; package com.bpgroup.poc.admin.app.authentication.exception;
public class DoNotHaveAnyMenuException extends Exception { public class DoNotHaveAnyMenuException extends Exception {
public DoNotHaveAnyMenuException() { public DoNotHaveAnyMenuException() {

View File

@ -1,4 +1,4 @@
package com.bpgroup.poc.admin.security.authentication.service.exception; package com.bpgroup.poc.admin.app.authentication.exception;
public class InvalidPasswordException extends Exception { public class InvalidPasswordException extends Exception {
public InvalidPasswordException(String message) { public InvalidPasswordException(String message) {

View File

@ -1,4 +1,4 @@
package com.bpgroup.poc.admin.security.authorization.service; package com.bpgroup.poc.admin.app.authorization;
import com.bpgroup.poc.admin.domain.base.admin.entity.Admin; import com.bpgroup.poc.admin.domain.base.admin.entity.Admin;
import com.bpgroup.poc.admin.domain.base.admin.entity.AdminRepository; import com.bpgroup.poc.admin.domain.base.admin.entity.AdminRepository;

View File

@ -1,4 +1,4 @@
package com.bpgroup.poc.admin.fitler; package com.bpgroup.poc.admin.filter;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;

View File

@ -3,10 +3,10 @@ package com.bpgroup.poc.admin.security;
import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationEntryPoint; import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationEntryPoint;
import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationFilter; import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationFilter;
import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationProvider; import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationProvider;
import com.bpgroup.poc.admin.security.authentication.service.LoginService; import com.bpgroup.poc.admin.app.authentication.AuthenticationService;
import com.bpgroup.poc.admin.security.authorization.CustomAccessDeniedHandler; import com.bpgroup.poc.admin.security.authorization.CustomAccessDeniedHandler;
import com.bpgroup.poc.admin.security.authorization.CustomAuthorizationManager; import com.bpgroup.poc.admin.security.authorization.CustomAuthorizationManager;
import com.bpgroup.poc.admin.security.authorization.service.AuthorizationService; import com.bpgroup.poc.admin.app.authorization.AuthorizationService;
import com.bpgroup.poc.admin.security.jwt.JwtTokenConstants; import com.bpgroup.poc.admin.security.jwt.JwtTokenConstants;
import com.bpgroup.poc.admin.security.jwt.JwtTokenValidateFilter; import com.bpgroup.poc.admin.security.jwt.JwtTokenValidateFilter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -36,7 +36,7 @@ public class SecurityConfig {
private static final String LOGOUT_PATH = "/logout"; private static final String LOGOUT_PATH = "/logout";
private static final String ERROR_PATH = "/error"; private static final String ERROR_PATH = "/error";
private final LoginService loginService; private final AuthenticationService authenticationService;
private final AuthorizationService authorizationService; private final AuthorizationService authorizationService;
@ -89,7 +89,7 @@ public class SecurityConfig {
@Bean @Bean
public CustomAuthenticationProvider customAuthenticationProvider() { public CustomAuthenticationProvider customAuthenticationProvider() {
return new CustomAuthenticationProvider(loginService); return new CustomAuthenticationProvider(authenticationService);
} }
@Bean @Bean

View File

@ -1,42 +0,0 @@
package com.bpgroup.poc.admin.security.authentication;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
public class AuthenticationDetail {
private String loginId;
private String name;
private String email;
@Builder
public static AuthenticationDetail of(String loginId, String name, String email) {
AuthenticationDetail authenticationDetail = new AuthenticationDetail();
authenticationDetail.loginId = loginId;
authenticationDetail.name = name;
authenticationDetail.email = email;
return authenticationDetail;
}
public String toJsonString() {
try {
return new ObjectMapper().writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static AuthenticationDetail fromJsonString(String jsonString) {
try {
return new ObjectMapper().readValue(jsonString, AuthenticationDetail.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -1,8 +1,8 @@
package com.bpgroup.poc.admin.security.authentication; package com.bpgroup.poc.admin.security.authentication;
import com.bpgroup.poc.admin.security.authentication.service.exception.AdminNotFoundException; import com.bpgroup.poc.admin.app.authentication.exception.AdminNotFoundException;
import com.bpgroup.poc.admin.security.authentication.service.exception.DoNotHaveAnyMenuException; import com.bpgroup.poc.admin.app.authentication.exception.DoNotHaveAnyMenuException;
import com.bpgroup.poc.admin.security.authentication.service.exception.InvalidPasswordException; import com.bpgroup.poc.admin.app.authentication.exception.InvalidPasswordException;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;

View File

@ -1,6 +1,6 @@
package com.bpgroup.poc.admin.security.authentication; package com.bpgroup.poc.admin.security.authentication;
import com.bpgroup.poc.admin.security.authentication.service.LoginResponse; import com.bpgroup.poc.admin.app.authentication.AuthenticationResponse;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@ -26,7 +26,7 @@ public class CustomAuthenticationFailureHandler implements AuthenticationFailure
} }
String jsonResponse = new ObjectMapper().writeValueAsString( String jsonResponse = new ObjectMapper().writeValueAsString(
LoginResponse.fail( AuthenticationResponse.fail(
"9999", "9999",
failMessage failMessage
) )

View File

@ -1,10 +1,11 @@
package com.bpgroup.poc.admin.security.authentication; package com.bpgroup.poc.admin.security.authentication;
import com.bpgroup.poc.admin.security.authentication.service.LoginRequest; import com.bpgroup.poc.admin.app.authentication.AuthenticationRequest;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@ -19,8 +20,7 @@ import java.nio.charset.StandardCharsets;
public class CustomAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public class CustomAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final String DEFAULT_LOGIN_REQUEST_URL = "/login"; private static final String DEFAULT_LOGIN_REQUEST_URL = "/login";
private static final String HTTP_METHOD = "POST"; private static final String HTTP_METHOD = "POST";
private static final String CONTENT_TYPE = "application/json"; private static final String CONTENT_TYPE = MediaType.APPLICATION_JSON_VALUE;
private boolean postOnly = true;
public CustomAuthenticationFilter() { public CustomAuthenticationFilter() {
super(new AntPathRequestMatcher(DEFAULT_LOGIN_REQUEST_URL, HTTP_METHOD)); // 위에서 설정한 /oauth2/login/* 요청에, GET으로 요청을 처리하기 위해 설정한다. super(new AntPathRequestMatcher(DEFAULT_LOGIN_REQUEST_URL, HTTP_METHOD)); // 위에서 설정한 /oauth2/login/* 요청에, GET으로 요청을 처리하기 위해 설정한다.
@ -33,13 +33,13 @@ public class CustomAuthenticationFilter extends AbstractAuthenticationProcessing
// 요청에 대한 유효성 검사 // 요청에 대한 유효성 검사
isValidated(request); isValidated(request);
LoginRequest loginRequest = new ObjectMapper().readValue( AuthenticationRequest authenticationRequest = new ObjectMapper().readValue(
StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8), StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8),
LoginRequest.class AuthenticationRequest.class
); );
String username = loginRequest.getUsername(); String username = authenticationRequest.getUsername();
String password = loginRequest.getPassword(); String password = authenticationRequest.getPassword();
if (username == null || password == null) { if (username == null || password == null) {
throw new AuthenticationServiceException("DATA IS MISS"); throw new AuthenticationServiceException("DATA IS MISS");
@ -52,7 +52,7 @@ public class CustomAuthenticationFilter extends AbstractAuthenticationProcessing
} }
private void isValidated(HttpServletRequest request) { private void isValidated(HttpServletRequest request) {
if (this.postOnly && !request.getMethod().equals(HTTP_METHOD)) { if (!request.getMethod().equals(HTTP_METHOD)) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
} }

View File

@ -1,7 +1,7 @@
package com.bpgroup.poc.admin.security.authentication; package com.bpgroup.poc.admin.security.authentication;
import com.bpgroup.poc.admin.security.authentication.service.LoginResult; import com.bpgroup.poc.admin.app.authentication.AuthenticationResult;
import com.bpgroup.poc.admin.security.authentication.service.LoginService; import com.bpgroup.poc.admin.app.authentication.AuthenticationService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -12,7 +12,7 @@ import org.springframework.transaction.annotation.Transactional;
@RequiredArgsConstructor @RequiredArgsConstructor
public class CustomAuthenticationProvider implements AuthenticationProvider { public class CustomAuthenticationProvider implements AuthenticationProvider {
private final LoginService loginService; private final AuthenticationService authenticationService;
@Transactional @Transactional
@Override @Override
@ -21,31 +21,20 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
String username = (String) authentication.getPrincipal(); String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials(); String password = (String) authentication.getCredentials();
LoginResult loginResult = loginService.login(username, password); AuthenticationResult authenticationResult = authenticationService.login(username, password);
return buildAuthenticationToken(loginResult); return buildAuthenticationToken(authenticationResult);
} catch (Exception e) { } catch (Exception e) {
throw new AuthenticationFailException("로그인에 실패하였습니다.", AuthenticationFailReason.from(e)); throw new AuthenticationFailException("로그인에 실패하였습니다.", AuthenticationFailReason.from(e));
} }
} }
private UsernamePasswordAuthenticationToken buildAuthenticationToken(LoginResult result) { private UsernamePasswordAuthenticationToken buildAuthenticationToken(AuthenticationResult result) {
UsernamePasswordAuthenticationToken token = UsernamePasswordAuthenticationToken.authenticated( return UsernamePasswordAuthenticationToken.authenticated(
result.getLoginId(), result.getLoginId(),
null, null,
null null
); );
token.setDetails(
AuthenticationDetail.builder()
.loginId(result.getLoginId())
.name(result.getName())
.email(result.getEmail())
.build()
.toJsonString()
);
return token;
} }
@Override @Override

View File

@ -1,6 +1,6 @@
package com.bpgroup.poc.admin.security.authentication; package com.bpgroup.poc.admin.security.authentication;
import com.bpgroup.poc.admin.security.authentication.service.LoginResponse; import com.bpgroup.poc.admin.app.authentication.AuthenticationResponse;
import com.bpgroup.poc.admin.security.jwt.JwtTokenGenerator; import com.bpgroup.poc.admin.security.jwt.JwtTokenGenerator;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.Cookie; import jakarta.servlet.http.Cookie;
@ -25,7 +25,7 @@ public class CustomAuthenticationSuccessHandler implements AuthenticationSuccess
response.addCookie(jwtCookie); response.addCookie(jwtCookie);
String jsonResponse = new ObjectMapper().writeValueAsString( String jsonResponse = new ObjectMapper().writeValueAsString(
LoginResponse.success() AuthenticationResponse.success()
); );
response.getWriter().write(jsonResponse); response.getWriter().write(jsonResponse);

View File

@ -1,28 +0,0 @@
package com.bpgroup.poc.admin.security.authentication.service;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
public class LoginResponse {
private String resultCode;
private String resultMessage;
private String token;
public static LoginResponse success() {
LoginResponse response = new LoginResponse();
response.resultCode = "0000";
response.resultMessage = "Success";
return response;
}
public static LoginResponse fail(String resultCode, String resultMessage) {
LoginResponse response = new LoginResponse();
response.resultCode = resultCode;
response.resultMessage = resultMessage;
return response;
}
}

View File

@ -1,20 +0,0 @@
package com.bpgroup.poc.admin.security.authentication.service;
import lombok.Getter;
@Getter
public class LoginResult {
private Long id;
private String loginId;
private String name;
private String email;
public static LoginResult of(Long id, String loginId, String name, String email) {
LoginResult loginResult = new LoginResult();
loginResult.id = id;
loginResult.loginId = loginId;
loginResult.name = name;
loginResult.email = email;
return loginResult;
}
}

View File

@ -1,41 +0,0 @@
package com.bpgroup.poc.admin.security.authentication.service;
import com.bpgroup.poc.admin.domain.base.admin.entity.Admin;
import com.bpgroup.poc.admin.domain.base.admin.entity.AdminRepository;
import com.bpgroup.poc.admin.security.authentication.service.exception.AdminNotFoundException;
import com.bpgroup.poc.admin.security.authentication.service.exception.DoNotHaveAnyMenuException;
import com.bpgroup.poc.admin.security.authentication.service.exception.InvalidPasswordException;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
@Service
@RequiredArgsConstructor
public class LoginService {
private final AdminRepository adminRepository;
private final PasswordEncoder passwordEncoder;
@Transactional
public LoginResult login(String username, String password) throws AdminNotFoundException, InvalidPasswordException, DoNotHaveAnyMenuException {
Optional<Admin> admin = adminRepository.findByLoginId(username);
if (admin.isEmpty()) {
throw new AdminNotFoundException(username);
}
if (!passwordEncoder.matches(password, admin.get().getPassword())) {
throw new InvalidPasswordException(username);
}
return LoginResult.of(
admin.get().getId(),
admin.get().getLoginId(),
admin.get().getName(),
admin.get().getLoginId()
);
}
}

View File

@ -1,6 +1,6 @@
package com.bpgroup.poc.admin.security.authorization; package com.bpgroup.poc.admin.security.authorization;
import com.bpgroup.poc.admin.security.authorization.service.AuthorizationService; import com.bpgroup.poc.admin.app.authorization.AuthorizationService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.authorization.AuthorizationManager;