Skip to content

Commit 2117baa

Browse files
authored
feat: 지원서 전체 현황 관리자만 볼 수 있게 aop 적용 (#254)
1 parent 90cee69 commit 2117baa

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

src/main/java/com/example/solidconnection/application/controller/ApplicationController.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.example.solidconnection.application.service.ApplicationQueryService;
77
import com.example.solidconnection.application.service.ApplicationSubmissionService;
88
import com.example.solidconnection.custom.resolver.AuthorizedUser;
9+
import com.example.solidconnection.custom.security.annotation.RequireAdminAccess;
910
import com.example.solidconnection.siteuser.domain.SiteUser;
1011
import jakarta.validation.Valid;
1112
import lombok.RequiredArgsConstructor;
@@ -38,6 +39,7 @@ public ResponseEntity<ApplicationSubmissionResponse> apply(
3839
.body(applicationSubmissionResponse);
3940
}
4041

42+
@RequireAdminAccess
4143
@GetMapping
4244
public ResponseEntity<ApplicationsResponse> getApplicants(
4345
@AuthorizedUser SiteUser siteUser,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.example.solidconnection.custom.security.annotation;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Target(ElementType.METHOD)
9+
@Retention(RetentionPolicy.RUNTIME)
10+
public @interface RequireAdminAccess {
11+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.example.solidconnection.custom.security.aspect;
2+
3+
import com.example.solidconnection.custom.exception.CustomException;
4+
import com.example.solidconnection.custom.security.annotation.RequireAdminAccess;
5+
import com.example.solidconnection.siteuser.domain.SiteUser;
6+
import lombok.RequiredArgsConstructor;
7+
import org.aspectj.lang.ProceedingJoinPoint;
8+
import org.aspectj.lang.annotation.Around;
9+
import org.aspectj.lang.annotation.Aspect;
10+
import org.springframework.stereotype.Component;
11+
12+
import static com.example.solidconnection.custom.exception.ErrorCode.ACCESS_DENIED;
13+
import static com.example.solidconnection.type.Role.ADMIN;
14+
15+
@Aspect
16+
@Component
17+
@RequiredArgsConstructor
18+
public class AdminAuthorizationAspect {
19+
20+
@Around("@annotation(requireAdminAccess)")
21+
public Object checkAdminAccess(ProceedingJoinPoint joinPoint,
22+
RequireAdminAccess requireAdminAccess) throws Throwable {
23+
SiteUser siteUser = null;
24+
for (Object arg : joinPoint.getArgs()) {
25+
if (arg instanceof SiteUser) {
26+
siteUser = (SiteUser) arg;
27+
break;
28+
}
29+
}
30+
if (siteUser == null || !ADMIN.equals(siteUser.getRole())) {
31+
throw new CustomException(ACCESS_DENIED);
32+
}
33+
return joinPoint.proceed();
34+
}
35+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package com.example.solidconnection.custom.security.aspect;
2+
3+
import com.example.solidconnection.custom.exception.CustomException;
4+
import com.example.solidconnection.custom.security.annotation.RequireAdminAccess;
5+
import com.example.solidconnection.siteuser.domain.SiteUser;
6+
import com.example.solidconnection.support.TestContainerSpringBootTest;
7+
import com.example.solidconnection.type.Gender;
8+
import com.example.solidconnection.type.PreparationStatus;
9+
import com.example.solidconnection.type.Role;
10+
import org.junit.jupiter.api.DisplayName;
11+
import org.junit.jupiter.api.Test;
12+
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.boot.test.context.TestConfiguration;
14+
import org.springframework.context.annotation.Bean;
15+
import org.springframework.stereotype.Component;
16+
17+
import static com.example.solidconnection.custom.exception.ErrorCode.ACCESS_DENIED;
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode;
20+
21+
@TestContainerSpringBootTest
22+
@DisplayName("어드민 권한 검사 Aspect 테스트")
23+
class AdminAuthorizationAspectTest {
24+
25+
@Autowired
26+
private TestService testService;
27+
28+
@Test
29+
void 어드민_사용자는_어드민_전용_메소드에_접근할_수_있다() {
30+
// given
31+
SiteUser adminUser = createSiteUser(Role.ADMIN);
32+
33+
// when
34+
boolean response = testService.adminOnlyMethod(adminUser);
35+
36+
// then
37+
assertThat(response).isTrue();
38+
}
39+
40+
@Test
41+
void 일반_사용자가_어드민_전용_메소드에_접근하면_예외_응답을_반환한다() {
42+
// given
43+
SiteUser mentorUser = createSiteUser(Role.MENTOR);
44+
45+
// when & then
46+
assertThatCode(() -> testService.adminOnlyMethod(mentorUser))
47+
.isInstanceOf(CustomException.class)
48+
.hasMessage(ACCESS_DENIED.getMessage());
49+
}
50+
51+
@Test
52+
void 어드민_어노테이션이_없는_메소드는_모두_접근_가능하다() {
53+
// given
54+
SiteUser menteeUser = createSiteUser(Role.MENTEE);
55+
SiteUser adminUser = createSiteUser(Role.ADMIN);
56+
57+
// when
58+
boolean menteeResponse = testService.publicMethod(menteeUser);
59+
boolean adminResponse = testService.publicMethod(adminUser);
60+
61+
// then
62+
assertThat(menteeResponse).isTrue();
63+
assertThat(adminResponse).isTrue();
64+
}
65+
66+
private SiteUser createSiteUser(Role role) {
67+
return new SiteUser(
68+
"test@example.com",
69+
"nickname",
70+
"profileImageUrl",
71+
"1999-01-01",
72+
PreparationStatus.CONSIDERING,
73+
role,
74+
Gender.MALE
75+
);
76+
}
77+
78+
@TestConfiguration
79+
static class TestConfig {
80+
81+
@Bean
82+
public TestService testService() {
83+
return new TestService();
84+
}
85+
}
86+
87+
@Component
88+
static class TestService {
89+
90+
@RequireAdminAccess
91+
public boolean adminOnlyMethod(SiteUser siteUser) {
92+
return true;
93+
}
94+
95+
public boolean publicMethod(SiteUser siteUser) {
96+
return true;
97+
}
98+
}
99+
}

0 commit comments

Comments
 (0)