代码硬编码
在代码中实现适用于简单的权限控制,一般只是限制是否登录,或有简单的角色
登录与不登录
http.authorizeRequests()
//不需要登录的路径
.antMatchers("/orders","/login").permitAll()
//其它需要
.anyRequest().authenticated();
简单角色
http.authorizeRequests()
//不需要登录的路径
.antMatchers("/orders","/login").permitAll()
//拥有ADMIN这个角色才能访问
.antMatchers("/manager").hasRole("ADMIN")
//其它需要
.anyRequest().authenticated();
//此时用户的GrantedAuthority 为ROLE_ADMIN
new User("admin", passwordEncoder.encode("123456"),"ROLE_SECRET");
在Restful API中,有可能针对同一个请求路径,不同的请求方式需要不同的权限,此外当URL中存在参数时 如DELETE请求 user/{userId} 都是删除用户,整体URL是变化的
http.authorizeRequests()
//路径匹配user/* 并且是delete请求 需要有ADMIN角色才能访问
.antMatchers(HttpMethod.DELETE,"/user/*").hasRole("ADMIN")
//其它需要
.anyRequest().authenticated();
或者也可以搭配使用
http.authorizeRequests()
.antMatchers(HttpMethod.DELETE,"/user/*").access("hasRole('ROLE_ADMIN') and hasRole('ROLE_SUPER') or hasIpAddress('127.0.0.1')")
.anyRequest().authenticated();
ExpressionUrlAuthorizationConfigurer 定义的权限表达式
从数据库获取
用户权限较复杂时,不可能把每个url需要啥权限都配置在代码里,配置在代码里也无法实现动态的修改权限,实现方式貌似有两种,一种是重写 SecurityMetadataSource 和 AccessDecisionManager ,在springSecurity过滤器链中,最后一个过滤器FilterSecurityInterceptor 中会调用 AccessDecisionManager 的 decide 方法,来确定当前请求是否通过.这种方法写着比较难受,网上也有很多,就不写了.另一种就是利用SPEL 如下,表达式内的方法在 WebExpressionVoter 的 vote方法中被调用
@Component("accessDecisionService")
public class AccessDecisionService {
private AntPathMatcher antPathMatcher = new AntPathMatcher();
public boolean hasPermission(HttpServletRequest request, Authentication auth){
UserDetails user = (UserDetails) auth.getPrincipal();
String userName=user.getUsername();
List urls=new ArrayList<>();
//todo: 根据用户名查出能访问哪些url, urls=findUrlByUserName()
for (String url : urls) {
if (antPathMatcher.match(url, request.getRequestURI())){
return true;
}
}
return false;
}
}
http.authorizeRequests()
.anyRequest()
.access("@accessDecisionService.hasPermission(request , authentication)");