spring security是一款安全框架,其原理是驗證客戶端與服務端的數據是否一致,這個數據可以是令牌也可以是用戶名與密碼的組合,那麼其工作原理是什麼樣,帶着這樣的疑問,我使用debug模式進行了驗證;
首先導入包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
@RestController
public class HelloWorld {
@RequestMapping("/Hello")
public String HelloController() {
return "Hello World!";
}
}
訪問localhost:8080/Hello,發現出現login表單的驗證畫面(用戶user,密碼會顯示在控制檯),說明框架已經起作用了;
查詢資料,spring security核心組件有:SecurityContext、SecurityContextHolder、Authentication、Userdetails 和 AuthenticationManager。
Authentication主要存放的是前端表單輸入的信息;
Userdetails 是一個接口,存放的是從數據庫裏面取出的角色數據,需要實現getAuthorities()方法;
UserDetailsService也是一個接口,存放的是從數據庫裏面取出的數據(用戶名,密碼,角色),需要實現loadUserByUsername(String username)方法;
現在前後端的數據全部有了,其驗證的程序在哪?我們沒有寫驗證程序卻可以進行表單驗證,spring security默認缺省的驗證程序是org.springframework.security.authentication.ProviderManager(AuthenticationManager的實現類):
private List<AuthenticationProvider> providers = Collections.emptyList();
<AuthenticationProvider>默認的實例化對象是:DaoAuthenticationProvider,可以看到該代碼裏面有如下內容:
@SuppressWarnings("deprecation")
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
String presentedPassword = authentication.getCredentials().toString();
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
}
if (authentication.getCredentials() == null) { :這裏驗證用戶名是否爲空;
if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { : 這裏驗證密碼,presentedPassword是前端傳進來的密碼,userDetails.getPassword()是數據庫中傳進來的密碼(已經加密過,其加密方式需要與passwordEncoder加密飯方式相同);
簡單的驗證就這樣完成了;
出現的問題:
1、驗證完成後,報403錯誤,這個錯誤查詢下來是權限不足,在SecurityConfig(extends WebSecurityConfigurerAdapter)裏面設置了http.authorizeRequests().antMatchers("/**").hasRole("ADMIN");在getAuthorities()(UserDetails的實現類)方法裏面也設置了 collection.add(new SimpleGrantedAuthority(role));
解決辦法是:將new SimpleGrantedAuthority(role)改爲:new SimpleGrantedAuthority("ROLE_"+role),這是這個框架的規則;