Skip to content

Commit

Permalink
feat: 이메일 기반 로그인 정책 기능 추가 #182
Browse files Browse the repository at this point in the history
추후 베타테스터에 대한 접근 제한 및 서비스 제한적 사용으로 로그인 정책을 추가해야 할 것에 대비
  • Loading branch information
seungyeop-lee committed Jul 24, 2024
1 parent 0bcfaef commit f7bd7f8
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 0 deletions.
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

0 comments on commit f7bd7f8

Please sign in to comment.