5.3 KiB
5.3 KiB
Java Spring Security Implementation
Enterprise RBAC with Spring Security and method-level security.
package com.example.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt());
return http.build();
}
}
Custom Permission Service
package com.example.security;
import org.springframework.stereotype.Service;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
@Service
public class AccessControlService {
private final Map<String, Set<String>> rolePermissions = new HashMap<>();
public AccessControlService() {
rolePermissions.put("ADMIN", Set.of(
"users:read", "users:write", "users:delete",
"reports:read", "reports:write",
"settings:read", "settings:write"
));
rolePermissions.put("MANAGER", Set.of(
"users:read", "users:write",
"reports:read", "reports:write"
));
rolePermissions.put("USER", Set.of(
"users:read",
"reports:read"
));
}
public boolean hasPermission(String role, String resource, String action) {
String permission = resource + ":" + action;
Set<String> permissions = rolePermissions.get(role);
return permissions != null && permissions.contains(permission);
}
public boolean canAccessResource(User user, String resourceOwnerId) {
// Check if user owns the resource or is admin
return user.getId().equals(resourceOwnerId) ||
user.getRoles().contains("ADMIN");
}
}
Method-Level Security
package com.example.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping
@PreAuthorize("hasRole('ADMIN') or hasAuthority('users:read')")
public List<User> getAllUsers() {
return userService.findAll();
}
@GetMapping("/{id}")
@PostAuthorize("returnObject.id == authentication.principal.id or hasRole('ADMIN')")
public User getUser(@PathVariable String id) {
return userService.findById(id);
}
@PutMapping("/{id}")
@PreAuthorize("@accessControlService.canAccessResource(authentication.principal, #id)")
public User updateUser(@PathVariable String id, @RequestBody User user) {
return userService.update(id, user);
}
@DeleteMapping("/{id}")
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(@PathVariable String id) {
userService.delete(id);
}
@PostMapping("/{id}/approve")
@PreAuthorize("hasRole('MANAGER') and @accessControlService.hasPermission(" +
"authentication.principal.role, 'users', 'approve')")
public User approveUser(@PathVariable String id) {
return userService.approve(id);
}
}
Custom Security Expression
package com.example.security;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.core.Authentication;
public class CustomMethodSecurityExpressionRoot
extends SecurityExpressionRoot
implements MethodSecurityExpressionOperations {
private Object filterObject;
private Object returnObject;
public CustomMethodSecurityExpressionRoot(Authentication authentication) {
super(authentication);
}
public boolean isResourceOwner(String resourceOwnerId) {
User user = (User) this.getPrincipal();
return user.getId().equals(resourceOwnerId);
}
public boolean hasDepartment(String department) {
User user = (User) this.getPrincipal();
return department.equals(user.getDepartment());
}
// Required interface methods
@Override
public void setFilterObject(Object filterObject) {
this.filterObject = filterObject;
}
@Override
public Object getFilterObject() {
return filterObject;
}
@Override
public void setReturnObject(Object returnObject) {
this.returnObject = returnObject;
}
@Override
public Object getReturnObject() {
return returnObject;
}
@Override
public Object getThis() {
return this;
}
}