Spring Security是一款强大的安全认证服务框架,它的原理就是在访问我们的系统前加了一系列的过滤器,可以称为过滤器链。它的两大核心就是认证和授权,本文主要描述的授权篇,认证篇请看https://www.jianshu.com/p/24c6a65c3913。那废话不多说,我们接着认证篇继续开车吧(新手司机,请坐稳!持续更新)
权限表达式
springsecurity是通过权限表达式控制授权,springsecurity的权限表达式及说明如下:
表达式 | 说明 |
---|---|
permitAll | 永远返回true |
denyAll | 永远返回false |
anonymous | 当前用户是anonymous时返回true |
rememberMe | 当前用户是rememberMe用户时返回true |
authenticated | 当前用户不是anonymous时返回true |
fullAuthenticated | 当前用户既不是anonymous也不是rememberMe用户时返回true |
hasRole(role) | 用户拥有指定的角色权限时返回true |
hasAnyRole([role1,role2]) | 用户拥有任意一个指定的角色权限时返回true |
hasAuthority(authority) | 用户拥有指定的权限时返回true |
hasAnyAuthority([authority1,authority2]) | 用户拥有任意一个指定的权限时返回true |
hasIpAddress('192.168.1.0') | 请求发送的Ip匹配时返回true |
接着认证部分的代码,在MySecurityConfig 的configure方法里添加需要的权限表达式:
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// http.httpBasic()
http.authorizeRequests()
.antMatchers("/hello.html")
.permitAll()//注意这里hello.html需要配置成不需要身份认证,否则会报重定向次数过多
.antMatchers("/user.html")
// .hasRole("ADMIN")//用hasRole时,在我们返回的UserDetails的Authority需要加Role_ADMIN
// .hasAuthority("read")//用户自定义的权限,返回的UserDetails的Authority只要与这里匹配就可以,这里不需要加ROLE_
// .access("hasRole('ADMIN') and hasIpAddress('192.168.0.1')")//指定有ADMIN权限并且匹配相应的IP
.access("@MyRbacService.findAuthority(request,authentication)")//指定我们自己写的方法控制权限
.and()
.formLogin()
.loginPage("/hello.html")//指定我们自己的登录页面
.loginProcessingUrl("/admin/login")//指定让UsernamePasswordAuthenticationFilter拦截器拦截的路径
.defaultSuccessUrl("/index")//默认登录成功后跳转的页面
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
http.csrf().disable();
http.headers().frameOptions().sameOrigin();
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
在强调一次,用hasRole时,在我们MyUserDetailService 返回的权限集合一定要加ROLE_ADMIN
@Component
public class MyUserDetailService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
return new User(name,passwordEncoder.encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN"));
}
}
在上面配置类里用到了access,可以拼接我们自己定义的权限表达式,也可以指定我们自己写的控制权限类如.access("@MyRbacService.findAuthority(request,authentication)")
自定义权限控制类之前需要在pom里添加两个依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
对应的Service,参数需要HttpServletRequest 和Authentication ,返回值一定要是boolean:
public interface MyRbacService {
boolean findAuthority(HttpServletRequest request, Authentication authentication);
}
实现类:
@Component("MyRbacService")
public class MyRbacServiceImpl implements MyRbacService {
private AntPathMatcher antPathMatcher=new AntPathMatcher();
@Override
public boolean findAuthority(HttpServletRequest request, Authentication authentication) {
boolean authority=false;
if (authentication.getPrincipal() instanceof UserDetails){
String username = ((UserDetails) authentication.getPrincipal()).getUsername();
//根据username去数据库查询对应的url,这里就不查了
List<String> list =new ArrayList();
for (String url:list){
if (antPathMatcher.match(url,request.getRequestURI())){
authority=true;
break;
}
}
return authority;
}
return authority;
}
}
上面代码需要在数据库创建用户表,权限表,对应url表,然后根据Authentication 里的username信息查找对应有权限的url去与当前请求url匹配,因为认证篇已经讲过,用户认证通过之后会把Authentication存在session里,所以认证过了Authentication 才会有用户信息。这里返回类型一定要是boolean,然后交给springsecurity处理。