-
Notifications
You must be signed in to change notification settings - Fork 37
[신성수] 인가(Authorization) 리뷰 요청 드립니다. #28
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
base: shinseongsu
Are you sure you want to change the base?
Changes from all commits
1dd4a35
cbaadb0
0106339
9ff668a
814f823
ac8a793
d682f6d
9f0f2fa
445bab9
f048ae3
686f74f
2c694df
a5e8768
0a0cdf2
b2297e9
78a77a0
b73d136
db26ae5
cd6fa2f
713f5eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,17 @@ | ||
# spring-security-authorization | ||
|
||
# 🚀 1단계 - AuthorizationManager를 활용 | ||
|
||
- [x] AuthorizationManager를 활용하여 인가 과정 추상화 | ||
- [x] SecuredAuthorizationManager 구현 | ||
- [x] RequestAuthorizationManager 구현 | ||
- [x] SecuredAuthorizationManager 구현 | ||
|
||
# 🚀 2단계 - 요청별 권한 검증 정보 분리 | ||
|
||
- [x] 요청별 권한 검증 정보를 별도의 객체로 분리하여 관리 | ||
- [x] RequestMatcher 작성 | ||
- [x] AnyRequestMatcher 구현 | ||
- [x] MvcRequestMatcher 구현 | ||
- [x] RequestMatcherEntry 작성 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,16 @@ | ||
package nextstep.app; | ||
|
||
import jakarta.servlet.http.HttpServletRequest; | ||
import nextstep.app.domain.Member; | ||
import nextstep.app.domain.MemberRepository; | ||
import nextstep.security.authentication.AuthenticationException; | ||
import nextstep.security.authentication.BasicAuthenticationFilter; | ||
import nextstep.security.authentication.UsernamePasswordAuthenticationFilter; | ||
import nextstep.security.authorization.AuthorizationFilter; | ||
import nextstep.security.authorization.CheckAuthenticationFilter; | ||
import nextstep.security.authorization.SecuredAspect; | ||
import nextstep.security.authorization.SecuredMethodInterceptor; | ||
import nextstep.security.authorization.manager.*; | ||
import nextstep.security.config.DefaultSecurityFilterChain; | ||
import nextstep.security.config.DelegatingFilterProxy; | ||
import nextstep.security.config.FilterChainProxy; | ||
|
@@ -22,6 +25,10 @@ | |
import java.util.List; | ||
import java.util.Set; | ||
|
||
import static nextstep.security.authorization.matcher.RequestMatcherEntry.createDefaultMatcher; | ||
import static nextstep.security.authorization.matcher.RequestMatcherEntry.createMvcMatcher; | ||
import static org.springframework.http.HttpMethod.GET; | ||
|
||
@EnableAspectJAutoProxy | ||
@Configuration | ||
public class SecurityConfig { | ||
|
@@ -46,19 +53,20 @@ public FilterChainProxy filterChainProxy(List<SecurityFilterChain> securityFilte | |
public SecuredMethodInterceptor securedMethodInterceptor() { | ||
return new SecuredMethodInterceptor(); | ||
} | ||
// @Bean | ||
// public SecuredAspect securedAspect() { | ||
// return new SecuredAspect(); | ||
// } | ||
|
||
@Bean | ||
public SecurityFilterChain securityFilterChain() { | ||
final AuthorizationManager<HttpServletRequest> authorizationManager = new RequestAuthorizationManager(List.of( | ||
createMvcMatcher(GET, "/members", new AuthorityAuthorizationManager<>("ADMIN")), | ||
createMvcMatcher(GET, "/members/me", new AuthenticatedAuthorizationManager<>()), | ||
createMvcMatcher(GET, "/search", new PermitAllAuthorizationManager<>()) | ||
), createDefaultMatcher(new DenyAllAuthorizationManager<>())); | ||
Comment on lines
+59
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 잘 추가해주셨네요 👍 |
||
return new DefaultSecurityFilterChain( | ||
List.of( | ||
new SecurityContextHolderFilter(), | ||
new UsernamePasswordAuthenticationFilter(userDetailsService()), | ||
new BasicAuthenticationFilter(userDetailsService()), | ||
new CheckAuthenticationFilter() | ||
new AuthorizationFilter(authorizationManager) | ||
) | ||
); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package nextstep.security.authorization; | ||
|
||
import jakarta.servlet.FilterChain; | ||
import jakarta.servlet.ServletException; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import nextstep.security.authentication.Authentication; | ||
import nextstep.security.authentication.AuthenticationException; | ||
import nextstep.security.authorization.manager.AuthorizationManager; | ||
import nextstep.security.context.SecurityContextHolder; | ||
import org.springframework.web.filter.OncePerRequestFilter; | ||
|
||
import java.io.IOException; | ||
|
||
public class AuthorizationFilter extends OncePerRequestFilter { | ||
private final AuthorizationManager<HttpServletRequest> authorizationManager; | ||
|
||
public AuthorizationFilter(AuthorizationManager<HttpServletRequest> authorizationManager) { | ||
this.authorizationManager = authorizationManager; | ||
} | ||
|
||
@Override | ||
protected void doFilterInternal( | ||
HttpServletRequest request, | ||
HttpServletResponse response, | ||
FilterChain filterChain | ||
) throws ServletException, IOException { | ||
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); | ||
if (authentication == null || !authentication.isAuthenticated()) { | ||
throw new AuthenticationException(); | ||
} | ||
if (!authorizationManager.authorize(authentication, request).isGranted()) { | ||
throw new ForbiddenException(); | ||
} | ||
filterChain.doFilter(request, response); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package nextstep.security.authorization.manager; | ||
|
||
import nextstep.security.authentication.Authentication; | ||
|
||
import static nextstep.security.authorization.manager.AuthorizationDecision.GRANTED; | ||
import static nextstep.security.authorization.manager.AuthorizationDecision.NOT_GRANTED; | ||
|
||
public class AuthenticatedAuthorizationManager<T> implements AuthorizationManager<T> { | ||
@Override | ||
public AuthorizationResult authorize(Authentication authentication, T target) { | ||
if(authentication != null && | ||
authentication.isAuthenticated() | ||
) { | ||
return GRANTED; | ||
} | ||
|
||
return NOT_GRANTED; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package nextstep.security.authorization.manager; | ||
|
||
import nextstep.security.authentication.Authentication; | ||
|
||
import java.util.Set; | ||
|
||
public class AuthorityAuthorizationManager<T> implements AuthorizationManager<T> { | ||
private final Set<String> authorities; | ||
|
||
public AuthorityAuthorizationManager(String... authorities) { | ||
this.authorities = Set.of(authorities); | ||
} | ||
|
||
@Override | ||
public AuthorizationResult authorize(Authentication authentication, T target) { | ||
return AuthorizationDecision.from(isGranted(authentication)); | ||
} | ||
|
||
private boolean isGranted(Authentication authentication) { | ||
return authentication != null | ||
&& authentication.isAuthenticated() | ||
&& anyMatch(authentication); | ||
} | ||
|
||
private boolean anyMatch(Authentication authentication) { | ||
return authentication.getAuthorities().stream() | ||
.anyMatch(authorities::contains); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package nextstep.security.authorization.manager; | ||
|
||
public enum AuthorizationDecision implements AuthorizationResult { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. true와 false로 구성되어있어 enum으로 생각해볼 수도 있으나 실제 구현체에서는 일반적으로 enum을 구성하는 것은 몇가지 고정값이 있기 때문에 enum으로 표현하지는 않고 정말 static한 정보들로 표기될때에만 사용되어요. 예를들면 그래서 사실은 |
||
GRANTED(true), | ||
NOT_GRANTED(false); | ||
|
||
private final boolean granted; | ||
|
||
AuthorizationDecision(final boolean granted) { | ||
this.granted = granted; | ||
} | ||
|
||
public boolean isGranted() { | ||
return this.granted; | ||
} | ||
|
||
public static AuthorizationResult from(boolean granted) { | ||
return granted ? GRANTED : NOT_GRANTED; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package nextstep.security.authorization.manager; | ||
|
||
import nextstep.security.authentication.Authentication; | ||
|
||
@FunctionalInterface | ||
public interface AuthorizationManager<T> { | ||
AuthorizationResult authorize(Authentication authentication, T target); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package nextstep.security.authorization.manager; | ||
|
||
public interface AuthorizationResult { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 미션내의 요구사항은 |
||
boolean isGranted(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package nextstep.security.authorization.manager; | ||
|
||
import nextstep.security.authentication.Authentication; | ||
|
||
import static nextstep.security.authorization.manager.AuthorizationDecision.NOT_GRANTED; | ||
|
||
public class DenyAllAuthorizationManager<T> implements AuthorizationManager<T> { | ||
@Override | ||
public AuthorizationResult authorize(Authentication authentication, T target) { | ||
return NOT_GRANTED; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package nextstep.security.authorization.manager; | ||
|
||
import nextstep.security.authentication.Authentication; | ||
|
||
import static nextstep.security.authorization.manager.AuthorizationDecision.GRANTED; | ||
|
||
public class PermitAllAuthorizationManager<T> implements AuthorizationManager<T> { | ||
@Override | ||
public AuthorizationResult authorize(Authentication authentication, T target) { | ||
return GRANTED; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
중복되어있네요 :)