-
Notifications
You must be signed in to change notification settings - Fork 0
[Refactor] AuthorizationService — 도메인 Service의 SCOPE 의존 제거 및 Strategy 패턴 도입 #99
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
Changes from all commits
cafeacf
faca7bb
564e265
24e4516
fe2dd87
6e3fadf
8a62f24
3c7cce2
81f1915
9eaa793
a4b7107
96f5668
7d4bfc1
5db2e70
719d9a7
afc7727
9d93f4a
6000b9e
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 |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.daedan.festabook.authorization; | ||
|
|
||
| public enum AccessAction { | ||
| CREATE, | ||
| READ, | ||
| UPDATE, | ||
| DELETE, | ||
| MANAGE, | ||
| NOTIFY | ||
| } | ||
|
Member
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. ROLETYPE을 그대로 쓰면 안 됐나요? 변경 지점이 두 군데인 것 같아요.. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package com.daedan.festabook.authorization; | ||
|
|
||
| public enum AccessSubject { | ||
| ORGANIZER, | ||
| STAFF, | ||
| PLACE_ACCESS | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| package com.daedan.festabook.authorization; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @SuppressWarnings("rawtypes") | ||
| public class AuthorizationContext { | ||
|
|
||
| private final Long scopeId; | ||
| private final List<Long> associatedIds; | ||
| private final Class resolverType; | ||
| private final Long principalId; | ||
|
Comment on lines
+6
to
+11
Member
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. 제가 볼때는 이건 변수명으로 유추가 불가능할 것 같거든요? 새로 들어온 개발자가 있다면? 이 부분은 주석을 활용해도 될 것 같은데 어떠세요? 그리고 각 Id 설명도 부탁드려요.. |
||
|
|
||
| private AuthorizationContext(Long scopeId, List<Long> associatedIds, Class<?> resolverType, Long principalId) { | ||
| this.scopeId = scopeId; | ||
| this.associatedIds = associatedIds; | ||
| this.resolverType = resolverType; | ||
| this.principalId = principalId; | ||
| } | ||
|
|
||
| public static AuthorizationContext ofScope(Long scopeId) { | ||
| return new AuthorizationContext(scopeId, null, null, null); | ||
| } | ||
|
|
||
| public static AuthorizationContext ofAssociated(List<Long> associatedIds, Class<?> resolverType) { | ||
| return new AuthorizationContext(null, associatedIds, resolverType, null); | ||
| } | ||
|
|
||
| public static AuthorizationContext ofAssociated(Long associatedId, Class<?> resolverType) { | ||
| return new AuthorizationContext(null, List.of(associatedId), resolverType, null); | ||
| } | ||
|
|
||
| public static AuthorizationContext ofScopeAndAssociated(Long scopeId, Long associatedId, Class<?> resolverType) { | ||
| return new AuthorizationContext(scopeId, List.of(associatedId), resolverType, null); | ||
| } | ||
|
|
||
| public static AuthorizationContext ofScopes(List<Long> scopeIds) { | ||
| return new AuthorizationContext(null, scopeIds, null, null); | ||
| } | ||
|
|
||
| public static AuthorizationContext ofPrincipal(Long principalId) { | ||
| return new AuthorizationContext(null, null, null, principalId); | ||
| } | ||
|
|
||
| public Long getScopeId() { | ||
| return scopeId; | ||
| } | ||
|
|
||
| public List<Long> getAssociatedIds() { | ||
| return associatedIds; | ||
| } | ||
|
|
||
| public Class getResolverType() { | ||
| return resolverType; | ||
| } | ||
|
|
||
| public Long getPrincipalId() { | ||
| return principalId; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.daedan.festabook.authorization; | ||
|
|
||
| public record AuthorizationKey( | ||
| Class<?> target, | ||
| AccessAction action, | ||
| AccessSubject subject | ||
| ) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.daedan.festabook.authorization; | ||
|
|
||
| import com.daedan.festabook.global.security.authorization.AccountDetails; | ||
|
|
||
| public interface AuthorizationStrategy { | ||
|
|
||
| boolean supports(AuthorizationKey key); | ||
|
|
||
| boolean isAuthorized(AccountDetails accountDetails, AuthorizationContext context); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package com.daedan.festabook.authorization.resolver; | ||
|
|
||
| import com.daedan.festabook.authorization.domain.FestivalIdsResolver; | ||
| import com.daedan.festabook.global.exception.InternalServerException; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.stream.Collectors; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Component | ||
| public class FestivalIdsResolverRegistry { | ||
|
|
||
| private final Map<Class<?>, FestivalIdsResolver> resolverMap; | ||
|
|
||
| public FestivalIdsResolverRegistry(List<FestivalIdsResolver> resolvers) { | ||
| this.resolverMap = resolvers.stream() | ||
| .collect(Collectors.toMap(FestivalIdsResolver::getResolverType, resolver -> resolver)); | ||
| } | ||
|
|
||
| public boolean hasResolver(Class<?> resolverType) { | ||
| return resolverMap.containsKey(resolverType); | ||
| } | ||
|
|
||
| public List<Long> resolve(Class<?> resolverType, List<Long> entityIds) { | ||
| FestivalIdsResolver resolver = resolverMap.get(resolverType); | ||
| if (resolver == null) { | ||
| throw new InternalServerException(); | ||
| } | ||
| return resolver.resolve(entityIds); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package com.daedan.festabook.authorization.resolver; | ||
|
|
||
| import com.daedan.festabook.authorization.domain.OrganizationIdResolver; | ||
| import com.daedan.festabook.global.exception.InternalServerException; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.stream.Collectors; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Component | ||
| public class OrganizationIdResolverRegistry { | ||
|
|
||
| private final Map<Class<?>, OrganizationIdResolver> resolverMap; | ||
|
|
||
| public OrganizationIdResolverRegistry(List<OrganizationIdResolver> resolvers) { | ||
| this.resolverMap = resolvers.stream() | ||
| .collect(Collectors.toMap(OrganizationIdResolver::getResolverType, resolver -> resolver)); | ||
| } | ||
|
|
||
| public boolean hasResolver(Class<?> resolverType) { | ||
| return resolverMap.containsKey(resolverType); | ||
| } | ||
|
|
||
| public Long resolve(Class<?> resolverType, Long entityId) { | ||
| OrganizationIdResolver resolver = resolverMap.get(resolverType); | ||
| if (resolver == null) { | ||
| throw new InternalServerException(); | ||
| } | ||
| return resolver.resolve(entityId) | ||
| .orElseThrow(InternalServerException::new); | ||
|
Comment on lines
+29
to
+30
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.
When Useful? React with 👍 / 👎. |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package com.daedan.festabook.authorization.resolver; | ||
|
|
||
| import com.daedan.festabook.authorization.domain.PlaceIdsResolver; | ||
| import com.daedan.festabook.global.exception.InternalServerException; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.stream.Collectors; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Component | ||
| public class PlaceIdsResolverRegistry { | ||
|
|
||
| private final Map<Class<?>, PlaceIdsResolver> resolverMap; | ||
|
|
||
| public PlaceIdsResolverRegistry(List<PlaceIdsResolver> resolvers) { | ||
| this.resolverMap = resolvers.stream() | ||
| .collect(Collectors.toMap(PlaceIdsResolver::getResolverType, resolver -> resolver)); | ||
| } | ||
|
|
||
| public boolean hasResolver(Class<?> resolverType) { | ||
| return resolverMap.containsKey(resolverType); | ||
| } | ||
|
|
||
| public List<Long> resolve(Class<?> resolverType, List<Long> entityIds) { | ||
| PlaceIdsResolver resolver = resolverMap.get(resolverType); | ||
| if (resolver == null) { | ||
| throw new InternalServerException(); | ||
| } | ||
| return resolver.resolve(entityIds); | ||
| } | ||
| } |
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.
저는 READ WRITE로 이전처럼 두개만 있는게 좋아보여요