Skip to content
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

feat: 이메일 기반 로그인 정책 기능 추가 #183

Merged
merged 1 commit into from
Jul 24, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandler;
import org.springframework.security.web.firewall.RequestRejectedHandler;
import vook.server.api.web.common.auth.app.TokenService;
import vook.server.api.web.common.auth.jwt.JWTFilter;
import vook.server.api.web.common.auth.oauth2.LoginPolicyChecker;
import vook.server.api.web.common.auth.oauth2.LoginSuccessHandler;
import vook.server.api.web.common.auth.oauth2.VookOAuth2UserService;

Expand Down Expand Up @@ -94,4 +97,16 @@ private static OAuth2AuthorizationRequestResolver authorizationRequestResolver(C
}));
return authorizationRequestResolver;
}

@Bean
public RequestRejectedHandler requestRejectedHandler() {
HttpStatusRequestRejectedHandler defaultHandler = new HttpStatusRequestRejectedHandler();
return (request, response, requestRejectedException) -> {
if (requestRejectedException instanceof LoginPolicyChecker.VookRequestRejectedException) {
response.sendRedirect(loginFailUrl);
} else {
defaultHandler.handle(request, response, requestRejectedException);
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package vook.server.api.web.common.auth.oauth2;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.web.firewall.RequestRejectedException;
import org.springframework.stereotype.Component;

@Component
public class LoginPolicyChecker {

private final Boolean loginRestrictionEnable;
private final String[] allowedEmails;

public LoginPolicyChecker(
@Value("${service.loginPolicy.loginRestriction.enable:false}")
Boolean loginRestrictionEnable,
@Value("${service.loginPolicy.loginRestriction.allowedEmails:}")
String[] allowedEmails
) {
this.loginRestrictionEnable = loginRestrictionEnable;
this.allowedEmails = allowedEmails;
}

public void check(OAuth2Response response) {
if (!loginRestrictionEnable) {
return;
}

// allowedEmails가 비어 있으면 모든 이메일을 허용
if (allowedEmails.length != 0 && !isAllowedEmail(response)) {
throw new VookRequestRejectedException("Not allowed email: " + response.getEmail());
}
}

private boolean isAllowedEmail(OAuth2Response response) {
for (String allowedEmail : this.allowedEmails) {
if (response.getEmail().equals(allowedEmail)) {
return true;
}
}
return false;
}

public static class VookRequestRejectedException extends RequestRejectedException {
public VookRequestRejectedException(String message) {
super(message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
public class VookOAuth2UserService extends DefaultOAuth2UserService {

private final UserLogic userLogic;
private final LoginPolicyChecker loginPolicyChecker;

@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
Expand All @@ -33,6 +34,8 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic
return null;
}

loginPolicyChecker.check(oAuth2Response);

return userLogic.findByProvider(oAuth2Response.getProvider(), oAuth2Response.getProviderId())
.map(VookLoginUser::from)
.orElseGet(() -> signUpUser(oAuth2Response));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package vook.server.api.web.common.response;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@Slf4j
@ControllerAdvice
public class GlobalControllerAdvice {

@Value("${service.oauth2.loginFailUrl}")
private String loginFailUrl;

@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
log.error(e.getMessage(), e);
return "redirect:" + loginFailUrl;
}
}
4 changes: 4 additions & 0 deletions server/api/src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,9 @@ service:
loginFailUrl: http://localhost:3000/auth?error
accessTokenExpiredMinute: 30 # 30 minutes
refreshTokenExpiredMinute: 10080 # 60 * 24 * 7 == 1 week
loginPolicy:
loginRestriction:
enable: false
allowedEmails: ""
logging:
config: classpath:logback.xml