最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot淺析安全管理之高級(jí)配置

 更新時(shí)間:2022年08月12日 15:33:57   作者:一只小熊貓呀  
安全管理是軟件系統(tǒng)必不可少的的功能。根據(jù)經(jīng)典的“墨菲定律”——凡是可能,總會(huì)發(fā)生。如果系統(tǒng)存在安全隱患,最終必然會(huì)出現(xiàn)問(wèn)題,這篇文章主要介紹了SpringBoot安全管理之高級(jí)配置

角色繼承

SpringBoot淺析安全管理之基于數(shù)據(jù)庫(kù)認(rèn)證中定義了三種角色,但是這三種角色之間不具備任何關(guān)系,一般來(lái)說(shuō)角色之間是有關(guān)系的,例如 ROLE_admin 一般既具有 admin 權(quán)限,又具有 user 權(quán)限。那么如何配置這種角色繼承關(guān)系呢?只需要開(kāi)發(fā)者在 Spring Security 的配置類中提供一個(gè) RoleHierarchy 即可

@Bean
RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
    String hierarchy = "ROLE_dba > ROLE_admin ROLE_admin > ROLE_user";
    roleHierarchy.setHierarchy(hierarchy);
    return roleHierarchy;
}

配置完 RoleHierarchy 之后,具有 ROLE_dba 角色的用戶就可以訪問(wèn) 所有資源了,具有 ROLE_admin 角色的用戶也可以訪問(wèn)具有 ROLE_user 角色才能訪問(wèn)的資源。

動(dòng)態(tài)權(quán)限配置

使用 HttpSecurity 配置的認(rèn)證授權(quán)規(guī)則還是不夠靈活,無(wú)法實(shí)現(xiàn)資源和角色之間的動(dòng)態(tài)調(diào)整,要實(shí)現(xiàn)動(dòng)態(tài)配置 URL 權(quán)限,需要開(kāi)發(fā)者自定義權(quán)限配置,配置步驟如下傳送門

1. 數(shù)據(jù)庫(kù)設(shè)計(jì)

在 10.2節(jié) 數(shù)據(jù)庫(kù)的基礎(chǔ)上再增加一張資源表和資源角色關(guān)聯(lián)表,資源表中定義了用戶能夠訪問(wèn)的 URL 模式,資源角色表則定義了訪問(wèn)該模式的 URL 需要什么樣的角色

建表語(yǔ)句

CREATE TABLE `menu` (
  `id` int(11) NOT NULL,
  `pattern` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `menu_role` (
  `id` int(11) NOT NULL,
  `mid` int(11) DEFAULT NULL,
  `rid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

初始化數(shù)據(jù)

INSERT INTO `menu`(`id`, `pattern`) VALUES (1, '/db/**');
INSERT INTO `menu`(`id`, `pattern`) VALUES (2, '/admin/**');
INSERT INTO `menu`(`id`, `pattern`) VALUES (3, '/user/**');
INSERT INTO `menu_role`(`id`, `mid`, `rid`) VALUES (1, 1, 1);
INSERT INTO `menu_role`(`id`, `mid`, `rid`) VALUES (2, 2, 2);
INSERT INTO `menu_role`(`id`, `mid`, `rid`) VALUES (3, 3, 3);

Menu 實(shí)體類

public class Menu {
    private Integer id;
    private String pattern;
    private List<Role> roles;
    public List<Role> getRoles() {
        return roles;
    }
    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getPattern() {
        return pattern;
    }
    public void setPattern(String pattern) {
        this.pattern = pattern;
    }
}

MenuMapper

@Mapper
public interface MenuMapper {
    List<Menu> getAllMenus();
}

MenuMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.sang.mapper.MenuMapper">
    <resultMap id="BaseResultMap" type="org.sang.model.Menu">
        <id property="id" column="id"/>
        <result property="pattern" column="pattern"/>
        <collection property="roles" ofType="org.sang.model.Role">
            <id property="id" column="rid"/>
            <result property="name" column="rname"/>
            <result property="nameZh" column="rnameZh"/>
        </collection>
    </resultMap>
    <select id="getAllMenus" resultMap="BaseResultMap">
        SELECT m.*,r.id AS rid,r.name AS rname,r.nameZh AS rnameZh FROM menu m LEFT JOIN menu_role mr ON m.`id`=mr.`mid` LEFT JOIN role r ON mr.`rid`=r.`id`
    </select>
</mapper>

2. 自定義FilterInvocationSecurityMetadataSource

Spring Security 中通過(guò) FilterInvocationSecurityMetadataSource 接口中的 getAttributes 方法來(lái)確定一個(gè)請(qǐng)求需要哪些角色,F(xiàn)ilterInvocationSecurityMetadataSource 接口默認(rèn)實(shí)現(xiàn)類是 DefaultFilterInvocationSecurityMetadataSource ,參考 DefaultFilterInvocationSecurityMetadataSource 的實(shí)現(xiàn),開(kāi)發(fā)者可以定義自己的 FilterInvocationSecurityMetadataSource ,如下:

@Component
public class CustomFilterInvocationSecurityMetadataSource
        implements FilterInvocationSecurityMetadataSource {
    AntPathMatcher antPathMatcher = new AntPathMatcher();
    @Autowired
    MenuMapper menuMapper;
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object)
            throws IllegalArgumentException {
        String requestUrl = ((FilterInvocation) object).getRequestUrl();
        List<Menu> allMenus = menuMapper.getAllMenus();
        for (Menu menu : allMenus) {
            if (antPathMatcher.match(menu.getPattern(), requestUrl)) {
                List<Role> roles = menu.getRoles();
                String[] roleArr = new String[roles.size()];
                for (int i = 0; i < roleArr.length; i++) {
                    roleArr[i] = roles.get(i).getName();
                }
                return SecurityConfig.createList(roleArr);
            }
        }
        return SecurityConfig.createList("ROLE_LOGIN");
    }
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }
    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
}

代碼解釋:

  • 開(kāi)發(fā)者自定義 FilterInvocationSecurityMetadataSource 主要實(shí)現(xiàn)接口中的 getAttributes 方法,該方法的參數(shù)是一個(gè) FilterInvocation ,開(kāi)發(fā)者可以從 FilterInvocation 中提取當(dāng)前請(qǐng)求的 URL ,返回值是 Collection,表示當(dāng)前請(qǐng)求 URL 所需角色
  • 創(chuàng)建一個(gè) AntPathMatcher 主要用來(lái)實(shí)現(xiàn) ant 風(fēng)格的 URL 匹配
  • ((FilterInvocation) object).getRequestUrl(); 從參數(shù)中提取當(dāng)前請(qǐng)求的 URL
  • menuMapper.getAllMenus(); 從數(shù)據(jù)庫(kù)中獲取所有的資源信息,即 menu 表以及 menu 所對(duì)應(yīng)的 role,在真實(shí)項(xiàng)目環(huán)境中,開(kāi)發(fā)者可以將資源信息緩存在 Redis 或者其他緩存數(shù)據(jù)庫(kù)中
  • 然后遍歷資源信息,遍歷過(guò)程中獲取當(dāng)前請(qǐng)求的 URL 所需要的角色信息并返回。如果當(dāng)前請(qǐng)求的 URL 在資源表中不存在相應(yīng)的模式,就假設(shè)該請(qǐng)求登錄后即可訪問(wèn),即直接返回 ROLE_LOGIN
  • getAllConfigAttributes 方法用來(lái)返回所有定義好的權(quán)限資源,Spring Security 在啟動(dòng)時(shí)會(huì)校驗(yàn)相關(guān)配置是否正確,如果不需要校驗(yàn),那么該方法直接返回 null 即可
  • supports 方法返回 類對(duì)象是否支持校驗(yàn)

3. 自定義 AccessDecisionManager

當(dāng)一個(gè)請(qǐng)求走完 FilterInvocationSecurityMetadataSource 中的 getAttributes 方法后,接下來(lái)就會(huì)來(lái)到 AccessDecisionManager 類中進(jìn)行角色信息的比對(duì),自定義 AccessDecisionManager 如下:

@Component
public class CustomAccessDecisionManager implements AccessDecisionManager {
    @Override
    public void decide(Authentication auth,
                       Object object,
                       Collection<ConfigAttribute> ca) {
        Collection<? extends GrantedAuthority> auths = auth.getAuthorities();
        for (ConfigAttribute configAttribute : ca) {
            if ("ROLE_LOGIN".equals(configAttribute.getAttribute())
                    && auth instanceof UsernamePasswordAuthenticationToken) {
                return;
            }
            for (GrantedAuthority authority : auths) {
                if (configAttribute.getAttribute().equals(authority.getAuthority())) {
                    return;
                }
            }
        }
        throw new AccessDeniedException("權(quán)限不足");
    }
    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }
    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}

代碼解釋:

  • 自定義 AccessDecisionManager 并重寫(xiě) decide 方法,在該方法中判斷當(dāng)前登錄的用戶是否具備當(dāng)前請(qǐng)求 URL 所需要的角色信息,如果不具備,就拋出 AccessDeniedException 異常,否則不做任何事情
  • decide 有三個(gè)參數(shù),第一個(gè)參數(shù)包含當(dāng)前登錄用戶的信息;第二個(gè)參數(shù)則是一個(gè) FilterInvocation 對(duì)象,可以獲取當(dāng)前請(qǐng)求對(duì)象等;第三個(gè)參數(shù)就是 UsernamePasswordAuthenticationToken 的實(shí)例,說(shuō)明當(dāng)前用戶已登錄,該方法到此結(jié)束,否則進(jìn)入正常的判斷流程,如果當(dāng)前用戶具備當(dāng)前請(qǐng)求需要的角色,那么方法結(jié)束

4. 配置

最后,在 Spring Security 中配置上邊的兩個(gè)自定義類,代碼如下:

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserService userService;
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }
    @Bean
    RoleHierarchy roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        String hierarchy = "ROLE_dba > ROLE_admin ROLE_admin > ROLE_user";
        roleHierarchy.setHierarchy(hierarchy);
        return roleHierarchy;
    }
    @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(cfisms());
                        object.setAccessDecisionManager(cadm());
                        return object;
                    }
                })
                .and()
                .formLogin()
                .loginProcessingUrl("/login").permitAll()
                .and()
                .csrf().disable();
    }
    @Bean
    CustomFilterInvocationSecurityMetadataSource cfisms() {
        return new CustomFilterInvocationSecurityMetadataSource();
    }
    @Bean
    CustomAccessDecisionManager cadm() {
        return new CustomAccessDecisionManager();
    }
}

代碼解釋:

  • 此處 WebSecurityConfig 類的定義是對(duì) 10.2節(jié) 中 WebSecurityConfig 定義的補(bǔ)充,主要修改了 configure(HttpSecurity http) 方法的實(shí)現(xiàn)并添加了兩個(gè) Bean
  • object.setSecurityMetadataSource(cfisms()); object.setAccessDecisionManager(cadm());將定義的兩個(gè)實(shí)例設(shè)置進(jìn)去

到此這篇關(guān)于SpringBoot淺析安全管理之高級(jí)配置的文章就介紹到這了,更多相關(guān)SpringBoot高級(jí)配置內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring Cloud 優(yōu)雅下線以及灰度發(fā)布實(shí)現(xiàn)

    Spring Cloud 優(yōu)雅下線以及灰度發(fā)布實(shí)現(xiàn)

    這篇文章主要介紹了Spring Cloud 優(yōu)雅下線以及灰度發(fā)布實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • spring boot 靜態(tài)資源處理方法

    spring boot 靜態(tài)資源處理方法

    本篇文章主要介紹了spring boot 靜態(tài)資源處理方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-03-03
  • spring?boot+mybatis-plus配置讀寫(xiě)分離的操作

    spring?boot+mybatis-plus配置讀寫(xiě)分離的操作

    這篇文章主要介紹了spring?boot+mybatis-plus配置讀寫(xiě)分離的操作,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2024-01-01
  • SpringBoot接口返回的數(shù)據(jù)時(shí)間與實(shí)際相差8小時(shí)問(wèn)題排查方式

    SpringBoot接口返回的數(shù)據(jù)時(shí)間與實(shí)際相差8小時(shí)問(wèn)題排查方式

    文章描述了在部署SpringBoot應(yīng)用到容器中時(shí)遇到請(qǐng)求接口返回時(shí)間與實(shí)際相差8小時(shí)的問(wèn)題,并詳細(xì)分析了可能的原因及具體的排查步驟和解決方案,總結(jié)指出,環(huán)境初始時(shí)區(qū)未配置是根本原因,建議在應(yīng)用部署前配置好時(shí)區(qū)
    2025-02-02
  • springboot項(xiàng)目數(shù)據(jù)庫(kù)密碼如何加密

    springboot項(xiàng)目數(shù)據(jù)庫(kù)密碼如何加密

    在我們?nèi)粘i_(kāi)發(fā)中,我們可能很隨意把數(shù)據(jù)庫(kù)密碼直接明文暴露在配置文件中,今天就來(lái)聊聊在springboot項(xiàng)目中如何對(duì)數(shù)據(jù)庫(kù)密碼進(jìn)行加密,感興趣的可以了解一下
    2021-07-07
  • Java實(shí)現(xiàn)簡(jiǎn)單的抽牌游戲

    Java實(shí)現(xiàn)簡(jiǎn)單的抽牌游戲

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡(jiǎn)單的抽牌游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • 學(xué)習(xí)Java之如何正確地向上轉(zhuǎn)型與向下轉(zhuǎn)型

    學(xué)習(xí)Java之如何正確地向上轉(zhuǎn)型與向下轉(zhuǎn)型

    面向?qū)ο蟮牡谌齻€(gè)特征是多態(tài),實(shí)現(xiàn)多態(tài)有三個(gè)必要條件:繼承、方法重寫(xiě)和向上轉(zhuǎn)型,在學(xué)習(xí)多態(tài)之前,我們還要先學(xué)習(xí)Java的類型轉(zhuǎn)換,本篇文章就來(lái)帶大家認(rèn)識(shí)什么是類型轉(zhuǎn)換,看看類型轉(zhuǎn)換都有哪幾種情況,以及如何避免類型轉(zhuǎn)換時(shí)出現(xiàn)異常
    2023-05-05
  • SWT(JFace)體驗(yàn)之ViewForm的使用

    SWT(JFace)體驗(yàn)之ViewForm的使用

    SWT(JFace)體驗(yàn)之ViewForm的使用
    2009-06-06
  • Spring定時(shí)任務(wù)使用及如何使用郵件監(jiān)控服務(wù)器

    Spring定時(shí)任務(wù)使用及如何使用郵件監(jiān)控服務(wù)器

    這篇文章主要介紹了Spring定時(shí)任務(wù)使用及如何使用郵件監(jiān)控服務(wù)器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • Java線程通信及線程虛假喚醒知識(shí)總結(jié)

    Java線程通信及線程虛假喚醒知識(shí)總結(jié)

    今天給大家?guī)?lái)的是關(guān)于Java線程的相關(guān)知識(shí),文章圍繞著Java線程通信及線程虛假喚醒的知識(shí)展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06

最新評(píng)論

赤峰市| 沂水县| 江都市| 荆门市| 沭阳县| 苏尼特左旗| 炉霍县| 如东县| 阳朔县| 民乐县| 闻喜县| 肥乡县| 郧西县| 乌鲁木齐市| 尖扎县| 五峰| 曲水县| 任丘市| 来凤县| 安福县| 大英县| 大足县| 宜昌市| 葵青区| 宾阳县| 麦盖提县| 友谊县| 开封县| 耿马| 滕州市| 阿荣旗| 玉林市| 廊坊市| 自治县| 霞浦县| 富锦市| 巩留县| 若羌县| 漳平市| 张家口市| 化德县|