spirng-boot中,基於既有的token驗證方式,利用spring-security實現許可權系統
用過spring-security的都應該能感覺到,spring-security把authentication和authorization封裝的比較死。預設的authorization是基於session的。利用session驗證過的資訊,儲存進SecurityContext,許可權系統再根據SecurityContext儲存的使用者許可權相關資訊,來進行許可權管理。
但是在目前的場景中,伺服器端往往要滿足多端的驗證方式,session的方式不容易和移動端配合的好。更多的是用一個token放在http header中進行驗證。這種就需要繞開spring-security預設的authentication直接利用它的authorization。
在這裡我演示一個在spring-security做方法級別攔截的方案。
這裡就是基於token的spring-boot安全攔截配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(1)
public class TokenBasedSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
try {
http.addFilterBefore(... SecurityContextPersistenceFilter.class);
http.securityContext().securityContextRepository(new SecurityContextRepository() {
@Override
public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
...
}
@Override
public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
...
}
@Override
public boolean containsContext(HttpServletRequest request) {
...
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
在這裡,我們要做的其實就是設定重在SecurityContextRepository
。這個實體在spring security啟動中要傳遞給SecurityContextPersistenceFilter
。這個filter根據request來載入SecurityContext
。而SecurityContextPersistenceFilter
就是從其內部的SecurityContextRepository
來載入SecurityContext
的。所以我們就需要過載上面程式碼中的三個方法,根據request來構造SecurityContext
。
我們再來看一下SecurityContext
到底封裝了什麼。
public interface SecurityContext extends Serializable {
Authentication getAuthentication();
void setAuthentication(Authentication authentication);
}
Authentication而已。
public interface Authentication extends Principal, Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
Object getCredentials();
Object getDetails();
Object getPrincipal();
boolean isAuthenticated();
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
在這裡我們還要構造一個機遇token的Authentication介面的實現。在實現中對於許可權來說很有用的就是getAuthorities
方法。我們只要給其封裝最簡單的SimpleGrantedAuthority
就好了。
這樣我們就可以給我們的Controller方法做攔截了~
@RestController
@RequestMapping(value = "test")
public class TestController {
@PreAuthorize("hasAuthority(`super_admin`)")
@RequestMapping(value = "hello", method = RequestMethod.GET)
public String superHello(@RequestParam String domain) {
return new String("super hello");
}
}