You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

@PostAuthorize失效问题:如何阻止用户访问其他用户的Item资源

我来帮你捋一捋这个@PostAuthorize不生效的问题哈,大概率是这几个点没注意到:

1. 先确认Spring Security方法安全是否开启

这是最容易被忽略的前提!@PreAuthorize、@PostAuthorize这类方法级安全注解默认是不启用的,你需要在Spring Security的配置类上加上@EnableGlobalMethodSecurity(prePostEnabled = true)注解才能让它们生效:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // 你的其他安全配置代码
}
2. 修正@PostAuthorize的表达式逻辑

你当前用#model['username']来做对比,其实可以更直接地引用model里的item对象,既省去额外往model塞username的步骤,也能避免可能的引用问题:

@PostAuthorize("principal.username == #model['item'].user.username")
@RequestMapping(value = "/show/{id}", method = RequestMethod.GET)
public String single(@PathVariable Long id, Model model) {
    Item item = itemService.findById(id);
    model.addAttribute("item", item);
    return "item";
}
3. 更优的思路:改用@PreAuthorize提前拦截

@PostAuthorize是方法执行完之后才做验证,也就是说不管用户有没有权限,item都会被查询出来,多少有点性能浪费和数据泄露风险。你可以换成@PreAuthorize,在方法执行前就完成权限校验:

方式一:直接在表达式中调用service

@PreAuthorize("principal.username == @itemService.findById(#id).user.username")
@RequestMapping(value = "/show/{id}", method = RequestMethod.GET)
public String single(@PathVariable Long id, Model model) {
    Item item = itemService.findById(id);
    model.addAttribute("item", item);
    return "item";
}

这里的@itemService是SpEL引用Spring Bean的语法,会直接调用service查询item并对比用户名。

方式二:封装权限校验方法避免重复查询

上面的方式会调用两次findById,你可以在service层加一个专门的权限校验方法:

// ItemService接口
boolean isItemOwnedByUser(Long itemId, String username);

// ItemServiceImpl实现
@Override
public boolean isItemOwnedByUser(Long itemId, String username) {
    Item item = findById(itemId);
    return item != null && username.equals(item.getUser().getUsername());
}

然后在控制器里用这个方法做校验:

@PreAuthorize("@itemService.isItemOwnedByUser(#id, principal.username)")
@RequestMapping(value = "/show/{id}", method = RequestMethod.GET)
public String single(@PathVariable Long id, Model model) {
    Item item = itemService.findById(id);
    model.addAttribute("item", item);
    return "item";
}
最后再确认下Principal的正确性

要确保当前用户的Authentication对象里的principal是包含username属性的对象(比如UserDetails的实现类),如果是自定义的用户对象,要保证它有public的getUsername()方法,这样SpEL才能正确读取principal.username。

按照上面的步骤排查,应该就能解决你的问题啦!

内容的提问来源于stack exchange,提问作者learnAndImprove

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:48:35