Spring Security自定义AccessDecisionManager实现指南及核心参数解析
你在自定义AccessDecisionManager时遇到的这两个参数确实是实现复杂授权逻辑的关键,我来给你拆解清楚它们的含义、用途和实际用法:
一、Object object:当前请求的「受保护对象」
含义与设计意图
这个参数代表当前触发授权检查的受保护资源,在Web场景下,它几乎总是FilterInvocation实例——因为Spring Security通过Filter链拦截HTTP请求,所以这里的object就是封装了当前HTTP请求、响应和FilterChain的对象。
实际用途
你可以通过它获取请求的详细信息,灵活定制授权规则,比如:
- 获取请求URL、HTTP方法
- 读取请求头、请求参数
- 获取客户端IP地址
- 直接拿到
HttpServletRequest和HttpServletResponse做更复杂的处理
示例代码
@Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException { // 先判断是否是Web请求场景的FilterInvocation if (object instanceof FilterInvocation) { FilterInvocation filterInvocation = (FilterInvocation) object; HttpServletRequest request = filterInvocation.getRequest(); // 获取请求URL和HTTP方法 String requestUrl = request.getRequestURI(); String httpMethod = request.getMethod(); // 获取客户端IP String clientIp = request.getRemoteAddr(); // 自定义规则:仅允许指定IP在POST方法下访问提交接口 if ("/api/submit".equals(requestUrl) && "POST".equals(httpMethod) && !"192.168.1.100".equals(clientIp)) { throw new AccessDeniedException("仅允许指定IP提交数据"); } } }
二、Collection configAttributes:当前资源要求的「权限配置」
含义与设计意图
这个集合代表当前受保护资源所要求的权限/配置属性——也就是你在Security配置里给某个URL(或方法)设置的访问规则,比如hasRole('ADMIN')、permitAll()这些规则,都会被解析成ConfigAttribute实例(通常是SecurityConfig实现类)。
实际用途
你可以通过它明确当前资源的访问要求,再和Authentication里的GrantedAuthorities(用户拥有的权限)做对比,实现自定义的权限匹配逻辑:
- 支持更灵活的权限表达式解析
- 自定义角色继承规则(比如让SUPER_ADMIN自动拥有ADMIN的权限)
- 基于多条件的组合授权判断
示例代码
假设你在Security配置里给URL设置了如下规则:
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasAnyRole("ADMIN", "SUPER_ADMIN") .antMatchers("/user/**").hasRole("USER"); }
当请求/admin/dashboard时,configAttributes里会包含两个SecurityConfig实例,分别对应ROLE_ADMIN和ROLE_SUPER_ADMIN。你的decide方法可以这样处理:
@Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException { // 如果资源不需要任何权限(比如permitAll()),直接放行 if (configAttributes == null || configAttributes.isEmpty()) { return; } // 获取当前用户的所有权限 Collection<? extends GrantedAuthority> userAuthorities = authentication.getAuthorities(); // 遍历资源要求的权限,检查用户是否拥有其中至少一个 for (ConfigAttribute attr : configAttributes) { String requiredAuthority = attr.getAttribute(); for (GrantedAuthority authority : userAuthorities) { if (requiredAuthority.equals(authority.getAuthority())) { // 用户拥有所需权限,直接放行 return; } } } // 没有匹配到任何权限,抛出拒绝访问异常 throw new AccessDeniedException("您没有访问该资源的权限"); }
额外场景:方法级授权下的参数变化
如果你的授权是基于方法级的(比如用@PreAuthorize注解),那么object会是MethodInvocation实例,你可以获取到当前调用的方法、参数等信息;而configAttributes则会包含注解里配置的权限表达式或规则。
比如方法上的注解:
@PreAuthorize("hasPermission(#order, 'EDIT')") public void editOrder(Order order) { // ... }
此时在decide方法里,你可以通过MethodInvocation拿到方法参数order,结合configAttributes里的权限规则,实现基于业务对象的细粒度授权判断。
内容的提问来源于stack exchange,提问作者hotmeatballsoup

