授權簡介
一般的人會認爲,不同的角色登錄進同一個系統,根據角色權限的不同,看到的菜單不同就是控制授權。其實並不是的,菜單的是否顯示只是前端交互上的一個設計而已,真正需要授權的地方的接口的訪問。
普通的系統通常會有兩個端,一個是給用戶用的業務系統(比如購物商城的買家端),一個是給公司運營人員用的管理端(可以統計銷售量,用戶量等信息)。
業務端的權限通常比較簡單,可以區分爲是否登錄,或者簡單的角色區分(比如普通用戶,VIP用戶)。管理端就相對複雜了,公司越大角色就越多,權限就分得越細緻。
是否登錄授權
之前在 SpringBoot + Spring Security 基本使用及個性化登錄配置中提到了普通的用戶登錄,這裏就配置了幾個接口是可以不用登錄就訪問的。這裏就不做過多的 介紹了
簡單角色的區分
同樣是在自己繼承了AbstractChannelSecurityConfig
類的configure方法中配置
@Configuration
public class BrowerSecurityConfig extends AbstractChannelSecurityConfig {
http.authorizeRequests() // 定義哪些URL需要被保護、哪些不需要被保護
.antMatchers("/user/regist", "/session/invalid")
.permitAll() // 設置所有人都可以訪問的接口
.antMatchers("/user").hasRole("ADMIN") // user接口只有ADMIN角色的可以訪問
.anyRequest() // 其他任何請求,登錄後可以訪問
.authenticated()
.and()
}
這裏主要通過antMatchers
和hasRole
搭配使用,進行角色權限的控制,那麼角色權限是在哪裏賦值的呢? 是在登錄管理那兒
@Component
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 演示用,隨便給一個password
String password = "123456";
// 參數分別是:用戶名,密碼,用戶權限
User user = new User(username, password, AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN));
return user;
}
}
AuthorityUtils.commaSeparatedStringToAuthorityList
接受一個字符串數組,裏面就是用戶的角色,比如在上面hasRole
裏配置的是”ADMIN”,則這裏需要傳入”ROLE_ADMIN”,ADMIN是要區分大小寫的。
在使用restfulAPI的時候,接口地址是一樣,但是請求方法不一樣,這個時候antMatchers
裏還可以配置請求方法
// 此時POST方法會需要角色權限
antMatchers(HttpMethod.POST, "/user").hasRole("ADMIN")
複雜角色權限 以及 權限表達式
之前的權限配置都是直接通過代碼寫在配置中的
當面對有複雜角色的時候,一般是把角色與權限放在數據庫中的。這個時候一般會涉及到五個數據庫表,分別是:用戶表、角色表、權限表,用戶與角色中間表,角色與權限中間表。
這裏我們模擬一個從數據庫中根據當前帳號獲取權限的示例
@Component("rbacPermission")
public class RbacPermission {
private AntPathMatcher antPathMatcher = new AntPathMatcher();
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
Object principal = authentication.getPrincipal();
boolean hasPermission = false;
if(principal instanceof UserDetails) {
String username = ((UserDetails) principal).getUsername();
// 讀取用戶所擁有的權限url,這裏應該從數據庫獲取
Set<String> urls = new HashSet<>();
for (String url : urls) {
// 判斷當前url是否有權限
if(antPathMatcher.match(url, request.getRequestURI())) {
hasPermission = true;
break;
}
}
}
return hasPermission;
}
}
接下來就是配置一下了
http.authorizeRequests()
.anyRequest()
.access("@rbacPermission.hasPermission(request, authentication)");
access
中的就是權限表達式
需要注意的是,anyRequest()需要放在最後