偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Spring Security 動(dòng)態(tài)權(quán)限與RBAC模型實(shí)戰(zhàn)

開(kāi)發(fā) 前端
權(quán)限控制是我們幾乎每個(gè)項(xiàng)目都要面對(duì)的問(wèn)題, 而Spring Security作為Spring生態(tài)中的安全框架, 提供了強(qiáng)大的支持. 但很多同學(xué)在使用時(shí)會(huì)遇到一些困惑, 特別是如何實(shí)現(xiàn)動(dòng)態(tài)權(quán)限控制, 今天我們就來(lái)詳細(xì)講一講.

權(quán)限控制是我們幾乎每個(gè)項(xiàng)目都要面對(duì)的問(wèn)題, 而Spring Security作為Spring生態(tài)中的安全框架, 提供了強(qiáng)大的支持. 但很多同學(xué)在使用時(shí)會(huì)遇到一些困惑, 特別是如何實(shí)現(xiàn)動(dòng)態(tài)權(quán)限控制, 今天我們就來(lái)詳細(xì)講一講.

一、權(quán)限控制概念

1) 什么是權(quán)限控制?

簡(jiǎn)單來(lái)說(shuō), 權(quán)限控制就是決定"誰(shuí)能在什么情況下對(duì)什么資源做什么操作". 比如: 

  1. 普通用戶只能查看自己的訂單
  2. 管理員可以查看所有訂單
  3. 只有財(cái)務(wù)人員才能導(dǎo)出財(cái)務(wù)報(bào)表

2) 常見(jiàn)的權(quán)限模型

ACL, ACL是最直接的權(quán)限模型, 它直接維護(hù)了"主體-資源-操作"的對(duì)應(yīng)關(guān)系. 比如: 

用戶

資源

操作

張三

/order

查看

李四

/report

導(dǎo)出

這種模型簡(jiǎn)單直接, 但當(dāng)用戶和資源數(shù)量增多時(shí), 維護(hù)成本會(huì)很高. 

RBAC(Role-Based Access Control)引入了"角色"這一中間層, 是目前最流行的權(quán)限模型. 它的核心思想是: 

  • 用戶關(guān)聯(lián)角色
  • 角色關(guān)聯(lián)權(quán)限
  • 權(quán)限決定能否訪問(wèn)資源

下面是ACL和RBAC的對(duì)比圖: 

圖片圖片

二、Spring Security中的RBAC實(shí)現(xiàn)

2.1 我們先看一個(gè)簡(jiǎn)單一點(diǎn)的實(shí)現(xiàn), 是基于配置的權(quán)限控制

1) 先來(lái)添加數(shù)據(jù)庫(kù)表: 

--用戶表
CREATE TABLE user (
    id BIGINT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(100) NOT NULL
);


--角色表
CREATE TABLE role (
    id BIGINT PRIMARY KEY,
    name VARCHAR(50) NOT NULL
);


--用戶-角色關(guān)聯(lián)表
CREATE TABLE user_role (
    user_id BIGINT,
    role_id BIGINT,
    PRIMARY KEY (user_id, role_id)
);


--權(quán)限表
CREATE TABLE permission (
    id BIGINT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    url VARCHAR(255) NOT NULL,
    description VARCHAR(200)
);


--角色-權(quán)限關(guān)聯(lián)表
CREATE TABLE role_permission (
    role_id BIGINT,
    permission_id BIGINT,
    PRIMARY KEY (role_id, permission_id)
);

2) 接著是配置Spring Security: 

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private UserDetailsService userDetailsService;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
            .antMatchers("/public/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .and()
            .logout().permitAll();
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    }
}

這種方式的優(yōu)點(diǎn)是簡(jiǎn)單直接, 但缺點(diǎn)是權(quán)限規(guī)則硬編碼在配置類中, 不夠靈活. 

2.2 實(shí)現(xiàn)動(dòng)態(tài)的權(quán)限控制

要實(shí)現(xiàn)真正的動(dòng)態(tài)權(quán)限(從數(shù)據(jù)庫(kù)加載權(quán)限規(guī)則), 我們需要自定義權(quán)限決策邏輯. 下面是實(shí)現(xiàn)步驟: 

1)  自定義FilterInvocationSecurityMetadataSource: 

@Component
public class DynamicSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {


    @Autowired
    private PermissionService permissionService;


    private Map<String, ConfigAttribute> permissionMap = null;


    /**
     * 加載所有權(quán)限規(guī)則
     */
    public void loadDataSource() {
        permissionMap = permissionService.getAllPermissionMap();
    }


    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        if (permissionMap == null) {
            this.loadDataSource();
        }


        HttpServletRequest request = ((FilterInvocation) object).getRequest();
        String url = request.getRequestURI();
        String method = request.getMethod();


        //去掉URL中的參數(shù)部分
        String path = url.split("\\?")[0];


        //嘗試直接匹配URL
        ConfigAttribute configAttribute = permissionMap.get(path + ":" + method);
        if (configAttribute != null) {
            return Collections.singletonList(configAttribute);
        }


        //嘗試通配符匹配
        for (String pattern : permissionMap.keySet()) {
            if (pathMatcher.match(pattern.split(":")[0], path) 
                && method.equalsIgnoreCase(pattern.split(":")[1])) {
                return Collections.singletonList(permissionMap.get(pattern));
            }
        }


        // 如果沒(méi)有匹配到, 返回一個(gè)標(biāo)記, 表示需要登錄但不需要特定權(quán)限
        return SecurityConfig.createList("ROLE_LOGIN");
    }


    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }


    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

2) 自定義AccessDecisionManager: 

@Component
public class DynamicAccessDecisionManager implements AccessDecisionManager {


    @Override
    public void decide(Authentication authentication, Object object, 
                       Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {


        //如果沒(méi)有權(quán)限規(guī)則,直接放行
        if (CollectionUtils.isEmpty(configAttributes)) {
            return;
        }


        //檢查每個(gè)需要的權(quán)限
        for (ConfigAttribute configAttribute : configAttributes) {
            String needRole = configAttribute.getAttribute();


            //只需要登錄的情況
            if ("ROLE_LOGIN".equals(needRole)) {
                if (authentication instanceof AnonymousAuthenticationToken) {
                    throw new AccessDeniedException("尚未登錄,請(qǐng)登錄");
                } else {
                    return;
                }
            }


            //檢查用戶是否有該角色
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            for (GrantedAuthority authority : authorities) {
                if (authority.getAuthority().equals(needRole)) {
                    return;
                }
            }
        }


        throw new AccessDeniedException("抱歉,您沒(méi)有訪問(wèn)權(quán)限");
    }


    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }


    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}

3) 更新Security配置: 

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    private DynamicSecurityMetadataSource dynamicSecurityMetadataSource;


    @Autowired
    private DynamicAccessDecisionManager dynamicAccessDecisionManager;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                @Override
                public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                    object.setSecurityMetadataSource(dynamicSecurityMetadataSource);
                    object.setAccessDecisionManager(dynamicAccessDecisionManager);
                    return object;
                }
            })
            .and()
            .formLogin()
            .and()
            .logout().permitAll();
    }


    // 其他配置...
}


責(zé)任編輯:武曉燕 來(lái)源: 全棧程序員老馬
相關(guān)推薦

2022-01-07 07:29:08

Rbac權(quán)限模型

2022-06-16 10:38:24

URL權(quán)限源代碼

2021-03-01 09:29:55

數(shù)據(jù)權(quán)限模型

2023-07-05 13:58:10

權(quán)限模型設(shè)計(jì)模式

2021-04-23 07:33:10

SpringSecurity單元

2022-08-30 08:50:07

Spring權(quán)限控制

2022-08-15 08:42:46

權(quán)限控制Spring

2022-08-30 08:43:11

Spring權(quán)限控制

2022-08-15 08:45:21

Spring權(quán)限控制

2022-08-30 08:55:49

Spring權(quán)限控制

2022-08-30 08:36:13

Spring權(quán)限控制

2012-08-20 10:40:01

IBMdW

2024-10-23 08:45:07

ACLABACRBAC

2020-09-16 08:07:54

權(quán)限粒度Spring Secu

2024-02-18 12:44:22

2024-10-17 09:14:24

RBAC模型管理

2022-05-05 10:40:36

Spring權(quán)限對(duì)象

2023-05-26 01:05:10

2021-04-19 07:33:04

WebSecuritySpringHttpSecurit

2021-01-28 09:50:29

分布式對(duì)象SharedObjec
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)