Spring Security是一款強(qiáng)大的安全認(rèn)證服務(wù)框架佩谣,它的原理就是在訪問我們的系統(tǒng)前加了一系列的過濾器干茉,可以稱為過濾器鏈捡偏。它的兩大核心就是認(rèn)證和授權(quán),本文主要描述的授權(quán)篇陷揪,認(rèn)證篇請看http://www.reibang.com/p/24c6a65c3913。那廢話不多說夷都,我們接著認(rèn)證篇繼續(xù)開車吧(新手司機(jī)产镐,請坐穩(wěn)!持續(xù)更新)
權(quán)限表達(dá)式
springsecurity是通過權(quán)限表達(dá)式控制授權(quán)九串,springsecurity的權(quán)限表達(dá)式及說明如下:
表達(dá)式 | 說明 |
---|---|
permitAll | 永遠(yuǎn)返回true |
denyAll | 永遠(yuǎn)返回false |
anonymous | 當(dāng)前用戶是anonymous時返回true |
rememberMe | 當(dāng)前用戶是rememberMe用戶時返回true |
authenticated | 當(dāng)前用戶不是anonymous時返回true |
fullAuthenticated | 當(dāng)前用戶既不是anonymous也不是rememberMe用戶時返回true |
hasRole(role) | 用戶擁有指定的角色權(quán)限時返回true |
hasAnyRole([role1绞佩,role2]) | 用戶擁有任意一個指定的角色權(quán)限時返回true |
hasAuthority(authority) | 用戶擁有指定的權(quán)限時返回true |
hasAnyAuthority([authority1,authority2]) | 用戶擁有任意一個指定的權(quán)限時返回true |
hasIpAddress('192.168.1.0') | 請求發(fā)送的Ip匹配時返回true |
接著認(rèn)證部分的代碼,在MySecurityConfig 的configure方法里添加需要的權(quán)限表達(dá)式:
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// http.httpBasic()
http.authorizeRequests()
.antMatchers("/hello.html")
.permitAll()//注意這里hello.html需要配置成不需要身份認(rèn)證猪钮,否則會報(bào)重定向次數(shù)過多
.antMatchers("/user.html")
// .hasRole("ADMIN")//用hasRole時品山,在我們返回的UserDetails的Authority需要加Role_ADMIN
// .hasAuthority("read")//用戶自定義的權(quán)限,返回的UserDetails的Authority只要與這里匹配就可以烤低,這里不需要加ROLE_
// .access("hasRole('ADMIN') and hasIpAddress('192.168.0.1')")//指定有ADMIN權(quán)限并且匹配相應(yīng)的IP
.access("@MyRbacService.findAuthority(request,authentication)")//指定我們自己寫的方法控制權(quán)限
.and()
.formLogin()
.loginPage("/hello.html")//指定我們自己的登錄頁面
.loginProcessingUrl("/admin/login")//指定讓UsernamePasswordAuthenticationFilter攔截器攔截的路徑
.defaultSuccessUrl("/index")//默認(rèn)登錄成功后跳轉(zhuǎn)的頁面
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
http.csrf().disable();
http.headers().frameOptions().sameOrigin();
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
在強(qiáng)調(diào)一次肘交,用hasRole時,在我們MyUserDetailService 返回的權(quán)限集合一定要加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扑馁,可以拼接我們自己定義的權(quán)限表達(dá)式涯呻,也可以指定我們自己寫的控制權(quán)限類如.access("@MyRbacService.findAuthority(request,authentication)")
自定義權(quán)限控制類之前需要在pom里添加兩個依賴
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
對應(yīng)的Service,參數(shù)需要HttpServletRequest 和Authentication 腻要,返回值一定要是boolean:
public interface MyRbacService {
boolean findAuthority(HttpServletRequest request, Authentication authentication);
}
實(shí)現(xiàn)類:
@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();
//根據(jù)username去數(shù)據(jù)庫查詢對應(yīng)的url,這里就不查了
List<String> list =new ArrayList();
for (String url:list){
if (antPathMatcher.match(url,request.getRequestURI())){
authority=true;
break;
}
}
return authority;
}
return authority;
}
}
上面代碼需要在數(shù)據(jù)庫創(chuàng)建用戶表复罐,權(quán)限表,對應(yīng)url表雄家,然后根據(jù)Authentication 里的username信息查找對應(yīng)有權(quán)限的url去與當(dāng)前請求url匹配效诅,因?yàn)檎J(rèn)證篇已經(jīng)講過,用戶認(rèn)證通過之后會把Authentication存在session里,所以認(rèn)證過了Authentication 才會有用戶信息填帽。這里返回類型一定要是boolean蛛淋,然后交給springsecurity處理。