Dynamic Access Control
I would like to share insights gained from implementing a feature in a project last year that allowed administrators to directly control access permissions for each resource.
From seamless permission updates without service interruption to database design, we will walk through how dynamic authorization can be efficiently implemented step by step through a real-world case.
1. Domain Design – Database Structure for Dynamic Authorization
The Menu domain designed to support dynamic authorization is structured as follows:
public class Menu {
private String id;
private String menuContext; // ex) admin:project:button
private List<String> permittedRoleCodes; // roles allowed to access this menu
}
The menuContext clearly defines the hierarchical structure of the service.
Additionally, the permission data stored in permittedRoleCodes provides the foundation for performing flexible authorization at runtime.
2. Backend – Implementing Dynamic Authorization with Spring AOP
A custom annotation (@PermissionCheckRequired) was defined, along with an Aspect to handle it.
The core idea of this approach is the complete separation of business logic and authorization logic.
The PermissionCheckRequiredAspect is responsible only for extracting annotation values, while the actual permission validation logic is delegated to an externally injected permissionConsumer. This design reduces coupling and improves maintainability.
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionCheckRequired {
String menuContext();
}
@Aspect
@RequiredArgConstructor
public class PermissionCheckRequiredAspect {
@Around("@annotation({packageName}.PermissionCheckRequired)")
public Object checkPermission(ProceddingJoinPoint point) throws Throwable {
// logic to extract annotation values
}
}
@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
@RequiredArgsConstructor
public class PermissionConfig {
private final ObjectProvider<Object> beanProvider;
private final UserSeek userSeek;
@Bean
public PermissionCheckRequiredAspect permissionCheckRequiredAspect() {
return new PermissionCheckRequiredAspect(menuContext -> {
// permission validation logic
}
}
Now, you only need to add this annotation to API methods that require authorization control.
This eliminates the need to repeatedly write complex permission checks within service logic.
@PostMapping("/sync-users/command")
@PermissionCheckRequired(menuContext = "admin:user:sync")
public CommandResponse syncUsers(@RequestBody SyncUsersCommand command) {
//business logic
}
3. Frontend – Menu Registration and Authorization Control Using Components
On the frontend, only permitted features should be exposed to users to reduce confusion and prevent security issues.
To achieve this, a reusable component (WithPermission) was created to control rendering based on permissions:
export const WithPermission = ({
children,
menuContext
}: {
children: ReactNode;
menuContext: string;
}) => {
const RenderByRoles = () => {
// permission check logic
return (
<RenderByRoles/>
);
}
This component can wrap entire pages or specific UI elements such as buttons.
It uses the same menuContext values defined in backend annotations to maintain consistency.
<WithPermission menuContext='admin:menu'>
<MenuPageView/>
</WithPermission>
Additionally, static analysis scripts can be used to automatically extract and register menu information from the project.
function extractWithPermissionProps(filePaths: string[]): MenuCdo[] {
for (const filePath of filePaths) {
const content = fs.readFileSync(filePath, 'utf-8');
const regex = /<WithPermission...>/g; // extract menu information
let match;
while ((match = regex.exec(content)) !== null) {
// register extracted menu
}
}
4. Conclusion – Benefits of Flexible Authorization Management
We have explored the full lifecycle of a dynamic authorization system, from database design to backend AOP and frontend automation through static analysis.
In the past, any change to menu access control required code modifications and redeployment.
However, with this approach, permissions can now be updated in real time, enabling immediate response to changing requirements without service disruption.
Hustle Paul