On this page
Shiro Authorization
Apache Shiro authorization controls access through roles (coarse-grained) and permissions (fine-grained string-based checks).
Permission Model
Permissions follow a resource:action convention:
order:create
order:read
order:update
order:delete
user:*
*:*
Wildcards:
order:*— all actions on orders*:*— all permissions (admin)
Checking Permissions
Subject subject = SecurityUtils.getSubject();
// Single permission
if (subject.isPermitted("order:create")) { createOrder(); }
// All required
if (subject.isPermittedAll("order:read", "order:update")) { updateOrder(); }
// Any one sufficient
if (subject.isPermitted("order:delete") || subject.hasRole("admin")) { deleteOrder(); }
// Role check
if (subject.hasRole("admin")) { /* admin action */ }
if (subject.hasAllRoles("admin", "manager")) { /* ... */ }
Annotation-Based Authorization
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.13.0</version>
</dependency>
@RequiresAuthentication
public class OrderController {
@RequiresPermissions("order:read")
@GetMapping("/orders/{id}")
public Order getOrder(@PathVariable Long id) { return orderService.findById(id); }
@RequiresPermissions("order:create")
@PostMapping("/orders")
public Order createOrder(@RequestBody CreateOrderRequest request) {
return orderService.create(request);
}
@RequiresRoles("admin")
@DeleteMapping("/orders/{id}")
public void deleteOrder(@PathVariable Long id) { orderService.delete(id); }
@RequiresPermissions(value = {"order:read", "order:update"}, logical = Logical.AND)
@PutMapping("/orders/{id}")
public Order updateOrder(@PathVariable Long id, @RequestBody UpdateOrderRequest req) {
return orderService.update(id, req);
}
}
Enable AOP:
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
URL-Based Authorization
In shiro.ini:
[urls]
/admin/** = roles[admin]
/api/orders/** = perms[order:read]
/api/orders/create = perms[order:create]
/api/** = authc
/** = anon
Filter order matters — first match wins.
Dynamic Permission Resolution
public class WildcardPermissionResolver implements PermissionResolver {
@Override
public Permission resolvePermission(String permissionString) {
return new WildcardPermission(permissionString);
}
}
Best Practices
- Use permissions over roles for fine-grained access control
- Apply
@RequiresAuthenticationat class level, specific permissions at method level - Define a consistent permission naming convention across the application
- Cache authorization info in the Realm to avoid repeated DB lookups
- Test authorization with Shiro’s
Subject.Builderin unit tests