赞
踩
欢迎来嫖从零开始SpringCloud Alibaba电商系列:
前几章,我们完善了权限系统的SSO登录认证以及redis共享session获取,但是对于一个权限要求灵活的后台管理系统来说还不够。
回想一下,我们之前是怎么控制一个接口的权限的:
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("apply02")
public String applyOrder02(){
return "权限专用测试";
}
http .authorizeRequests()
.antMatchers("/test/*","/order/*")
.hasAnyRole("admin")
可以发现一个问题,url的权限控制要么一个个硬编码在接口脑袋上,要么一个个硬编码在配置类,有没有什么方法可以让我们使用数据库来存储这些权限规则并动态的应用上呢?
这就是我们今天第一个要解决的问题,实际上网上有很多相关资料,但是基本上都是一样的,都是通过增加
一个spring security的过滤链中增加一个Filter,然后自定义一个权限决定器AccessDecisionManager和一个
权限数据加载器FilterInvocationSecurityMetadataSource,我觉得这种方式太过麻烦,于是自己想了一种
方法来更简单灵活的配置我们的权限系统。
AccessDecisionManager核心的方法是decide,它传入用户信息auth和当前访问的request进行一些决策
来决定当前用户是否可以访问当前资源。它一般的策略是通过权限加载器获得一些数据,然后根据这些数据进行一票通过、一票否决、多数通过的策略等,最后的结果是返回是否有权访问
。有兴趣的同学可以goole/百度一下具体的使用和原理。
而我直接将decide的方法换了一个定义:你已经给了我用户的权限信息和当前访问的url,我完全可以直接在这里根据用户的权限(在之前设计中用户的权限集合存放的就是资源的url)和url做一个比对,存在即可通过。
这种方法可以极大的减少代码量,只需要重写一个AccessDecisionManager,然后将其通过http配置一下就可以了。
@Component public class MallAccessDecisionManager implements AccessDecisionManager { /** * 若用户的权限中包含当前路径所需权限,则可以通过,否则认证异常 * @param authentication 用户认证信息,包含用户所拥有的权限 * @param object * @param configAttributes 访问当前路径所需要的权限 * @throws AccessDeniedException * @throws InsufficientAuthenticationException */ @Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if(configAttributes==null){ return; } String requestUrl = ((FilterInvocation)object).getRequestUrl() ; AntPathMatcher antPathMatcher = new AntPathMatcher(); for (GrantedAuthority authority : authentication.getAuthorities()) { // 字符串等于匹配 TODO 动态url if( authority.getAuthority().equals( requestUrl )) { return; } // ant匹配 if( antPathMatcher.match(authority.getAuthority(),requestUrl) ) {return;} // 对已登录用户放开属于当前服务器静态资源,其实只有swagger资源 boolean hasPower = authentication.isAuthenticated() && !authority.getAuthority().equals("ROLE_ANONYMOUS") && (antPathMatcher.match("/webjars/**",requestUrl) || (antPathMatcher.match("/swagger-resources",requestUrl)) || (antPathMatcher.match("/v2/api-docs",requestUrl)) || (antPathMatcher.match("/doc.html",requestUrl)) ); if( hasPower ) { return; } } throw new AccessDeniedException("抱歉,您没有访问权限"); } @Override public boolean supports(Class<?> clazz) { return true; } @Override public boolean supports(ConfigAttribute attribute) { return true; } }
@Bean public AccessDecisionManager accessDecisionManager(){ return new MallAccessDecisionManager(); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .accessDecisionManager(accessDecisionManager()) .and() .formLogin() .defaultSuccessUrl("/doc.html") .and() ; }
就这么简单,完事。
插入测试数据,在数据库权限表添加记录并关联到角色,角色关联到用户。
ps:这里只贴了一个权限表,其他表数据很简单不再贴出来,表结构在前文有说明。
打开 http://localhost:8082/login,登录。
访问接口,可以发现只有无参访问GET接口可以成功,配置成功。
剩下的数据就靠大家自由发挥了。
完整代码:
https://github.com/flyChineseBoy/lel-mall/tree/master/mall11
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。