SpringBoot + SpringSecurity 控制授權

授權簡介

一般的人會認爲,不同的角色登錄進同一個系統,根據角色權限的不同,看到的菜單不同就是控制授權。其實並不是的,菜單的是否顯示只是前端交互上的一個設計而已,真正需要授權的地方的接口的訪問。

普通的系統通常會有兩個端,一個是給用戶用的業務系統(比如購物商城的買家端),一個是給公司運營人員用的管理端(可以統計銷售量,用戶量等信息)。
業務端的權限通常比較簡單,可以區分爲是否登錄,或者簡單的角色區分(比如普通用戶,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()
}

這裏主要通過antMatchershasRole搭配使用,進行角色權限的控制,那麼角色權限是在哪裏賦值的呢? 是在登錄管理那兒

@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()需要放在最後

代碼下載

Spring-Security

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章