欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot整合SpringSecurityOauth2實(shí)現(xiàn)鑒權(quán)動(dòng)態(tài)權(quán)限問題

 更新時(shí)間:2022年06月20日 14:31:34   作者:Jae1995  
這篇文章主要介紹了SpringBoot整合SpringSecurityOauth2實(shí)現(xiàn)鑒權(quán)-動(dòng)態(tài)權(quán)限,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

寫在前面

思考:為什么需要鑒權(quán)呢?

系統(tǒng)開發(fā)好上線后,API接口會(huì)暴露在互聯(lián)網(wǎng)上會(huì)存在一定的安全風(fēng)險(xiǎn),例如:爬蟲、惡意訪問等。因此,我們需要對(duì)非開放API接口進(jìn)行用戶鑒權(quán),鑒權(quán)通過之后再允許調(diào)用。

準(zhǔn)備

spring-boot:2.1.4.RELEASE

spring-security-oauth2:2.3.3.RELEASE(如果要使用源碼,不要隨意改動(dòng)這個(gè)版本號(hào),因?yàn)?.4往上的寫法不一樣了)

mysql:5.7

效果展示

這邊只用了postman做測(cè)試,暫時(shí)未使用前端頁面來對(duì)接,下個(gè)版本角色菜單權(quán)限分配的會(huì)有頁面的展示

1、訪問開放接口http://localhost:7000/open/hello 

2、不帶token訪問受保護(hù)接口http://localhost:7000/admin/user/info

3、登錄后獲取token,帶上token訪問,成功返回了當(dāng)前的登錄用戶信息

實(shí)現(xiàn)

oauth2一共有四種模式,這邊就不做講解了,網(wǎng)上搜一搜,千篇一律

因?yàn)楝F(xiàn)在只考慮做單方應(yīng)用的,所以使用的是密碼模式。

后面會(huì)出一篇SpringCloud+Oauth2的文章,網(wǎng)關(guān)鑒權(quán)

講一下幾個(gè)點(diǎn)吧

1、攔截器配置動(dòng)態(tài)權(quán)限

新建一個(gè) MySecurityFilter類,繼承AbstractSecurityInterceptor,并實(shí)現(xiàn)Filter接口

初始化,自定義訪問決策管理器

@PostConstruct
 public void init(){
        super.setAuthenticationManager(authenticationManager);
        super.setAccessDecisionManager(myAccessDecisionManager);
  }  

自定義 過濾器調(diào)用安全元數(shù)據(jù)源

@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
    return this.mySecurityMetadataSource;
}

先來看一下自定義過濾器調(diào)用安全元數(shù)據(jù)源的核心代碼

以下代碼是用來獲取到當(dāng)前請(qǐng)求進(jìn)來所需要的權(quán)限(角色)

/**
     * 獲得當(dāng)前請(qǐng)求所需要的角色
     * @param object
     * @return
     * @throws IllegalArgumentException
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        String requestUrl = ((FilterInvocation) object).getRequestUrl();

        if (IS_CHANGE_SECURITY) {
            loadResourceDefine();
        }
        if (requestUrl.indexOf("?") > -1) {
            requestUrl = requestUrl.substring(0, requestUrl.indexOf("?"));
        }
        UrlPathMatcher matcher = new UrlPathMatcher();
        List<Object> list = new ArrayList<>();  //無需權(quán)限的,直接返回
        list.add("/oauth/**");
        list.add("/open/**");
        if(matcher.pathsMatchesUrl(list,requestUrl))
            return null;

        Set<String> roleNames = new HashSet();
        for (Resc resc: resources) {
            String rescUrl = resc.getResc_url();
            if (matcher.pathMatchesUrl(rescUrl, requestUrl)) {
                if(resc.getParent_resc_id() != null && resc.getParent_resc_id().intValue() == 1){   //默認(rèn)權(quán)限的則只要登錄了,無需權(quán)限匹配都可訪問
                    roleNames = new HashSet();
                    break;
                }
                Map map = new HashMap();
                map.put("resc_id", resc.getResc_id());
                // 獲取能訪問該資源的所有權(quán)限(角色)
                List<RoleRescDTO> roles = roleRescMapper.findAll(map);
                for (RoleRescDTO rr : roles)
                    roleNames.add(rr.getRole_name());
            }
        }

        Set<ConfigAttribute> configAttributes = new HashSet();
        for(String roleName:roleNames)
            configAttributes.add(new SecurityConfig(roleName));

        log.debug("【所需的權(quán)限(角色)】:" + configAttributes);

        return configAttributes;
    }

再來看一下自定義訪問決策管理器核心代碼,這段代碼主要是判斷當(dāng)前登錄用戶(當(dāng)前登錄用戶所擁有的角色會(huì)在最后一項(xiàng)寫到)是否擁有該權(quán)限角色

@Override
    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        if(configAttributes == null){   //屬于白名單的,不需要權(quán)限
            return;
        }
        Iterator<ConfigAttribute> iterator = configAttributes.iterator();
        while (iterator.hasNext()){
            ConfigAttribute configAttribute = iterator.next();
            String needPermission = configAttribute.getAttribute();
            for (GrantedAuthority ga: authentication.getAuthorities()) {
                if(needPermission.equals(ga.getAuthority())){   //有權(quán)限,可訪問
                    return;
                }
            }
        }
        throw new AccessDeniedException("沒有權(quán)限訪問");

    }

2、自定義鑒權(quán)異常返回通用結(jié)果

為什么需要這個(gè)呢,如果不配置這個(gè),對(duì)于前端,后端來說都很難去理解鑒權(quán)失敗返回的內(nèi)容,還不能統(tǒng)一解讀,廢話不多說,先看看不配置和配置了的返回情況

(1)未自定義前,沒有攜帶token去訪問受保護(hù)的API接口時(shí),返回的結(jié)果是這樣的

(2)我們規(guī)定一下,鑒權(quán)失敗的接口返回接口之后,變成下面這種了,是不是更利于我們處理和提示用戶

好了,來看一下是在哪里去配置的吧

我們資源服務(wù)器OautyResourceConfig,重寫下下面這部分的代碼,來自定義鑒權(quán)異常返回的結(jié)果

大伙可以參考下這個(gè)http://www.dbjr.com.cn/article/131668.htm

@Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.authenticationEntryPoint(authenticationEntryPoint)    //token失效或沒攜帶token時(shí)
                .accessDeniedHandler(requestAccessDeniedHandler);   //權(quán)限不足時(shí)
    }

3、獲取當(dāng)前登錄用戶

第一種:使用JWT攜帶用戶信息,拿到token后再解析

暫不做解釋

第二種:寫一個(gè)SecurityUser實(shí)現(xiàn)UserDetails接口(這個(gè)工程中使用的是這一種)

原來的只有UserDetails接口只有username和password,這里我們加上我們系統(tǒng)中的User

protected User user;
    public SecurityUser(User user) {
        this.user = user;
    }

    public User getUser() {
        return user;
    }

在BaseController,每個(gè)Controller都會(huì)繼承這個(gè)的,在里面寫給getUser()的方法,只要用戶帶了token來訪問,我們可以直接獲取當(dāng)前登錄用戶的信息了

protected User getUser() {
        try {
            SecurityUser userDetails = (SecurityUser) SecurityContextHolder.getContext().getAuthentication()
                    .getPrincipal();

            User user = userDetails.getUser();
            log.debug("【用戶:】:" + user);

            return user;
        } catch (Exception e) {
        }
        return null;
    }

那么用戶登錄成功后,如何去拿到用戶的角色集合等呢,這里面就要實(shí)現(xiàn)UserDetailsService接口了

@Service
public class TokenUserDetailsService implements UserDetailsService{

    @Autowired
    private LoginService loginService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = loginService.loadUserByUsername(username);  //這個(gè)我們拎出來處理
        if(Objects.isNull(user))
            throw new UsernameNotFoundException("用戶名不存在");
        return new SecurityUser(user);
    }
}

然后在我們的安全配置類中設(shè)置UserDetailsService為上面的我們自己寫的就行

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

最后我們只需要在loginService里面實(shí)現(xiàn)我們的方法就好,根據(jù)我們的實(shí)際業(yè)務(wù)處理判斷該用戶是否存在等

@Override
    public User loadUserByUsername(String username){
        log.debug(username);
        Map map = new HashMap();
        map.put("username",username);
        map.put("is_deleted",-1);
        User user = userMapper.findByUsername(map);
        if(user != null){
            map = new HashMap();
            map.put("user_id",user.getUser_id());
            //查詢用戶的角色
            List<UserRoleDTO> userRoles = userRoleMapper.findAll(map);
            user.setRoles(listRoles(userRoles));
            //權(quán)限集合
            Collection<? extends GrantedAuthority> authorities = merge(userRoles);
            user.setAuthorities(authorities);
            return user;
        }
        return null;

    }

大功告成啦,趕緊動(dòng)起手來吧!

附上源碼地址:https://gitee.com/jae_1995/spring-boot-oauth2

數(shù)據(jù)庫文件在這

到此這篇關(guān)于SpringBoot整合SpringSecurityOauth2實(shí)現(xiàn)鑒權(quán)-動(dòng)態(tài)權(quán)限的文章就介紹到這了,更多相關(guān)SpringBoot整合SpringSecurityOauth2內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入理解Java中的構(gòu)造函數(shù)引用和方法引用

    深入理解Java中的構(gòu)造函數(shù)引用和方法引用

    java構(gòu)造函數(shù),也叫構(gòu)造方法,是java中一種特殊的函數(shù)。函數(shù)名與相同,無返回值。方法引用是用來直接訪問類或者實(shí)例的已經(jīng)存在的方法或者構(gòu)造方法。下面我們來詳細(xì)了解一下它們吧
    2019-06-06
  • SpringBoot+WebSocket實(shí)現(xiàn)消息推送功能

    SpringBoot+WebSocket實(shí)現(xiàn)消息推送功能

    WebSocket協(xié)議是基于TCP的一種新的網(wǎng)絡(luò)協(xié)議。本文將通過SpringBoot集成WebSocket實(shí)現(xiàn)消息推送功能,感興趣的可以了解一下
    2022-08-08
  • 基于springboot搭建的web系統(tǒng)架構(gòu)的方法步驟

    基于springboot搭建的web系統(tǒng)架構(gòu)的方法步驟

    這篇文章主要介紹了基于springboot搭建的web系統(tǒng)架構(gòu)的方法步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-04-04
  • 基于java構(gòu)造方法Vector修改元素源碼分析

    基于java構(gòu)造方法Vector修改元素源碼分析

    本篇文章是關(guān)于ava構(gòu)造方法Vector源碼分析系列文章,本文主要介紹了Vector修改元素的源碼分析,有需要的朋友可以借鑒參考下,希望可以有所幫助
    2021-09-09
  • SpringAnimation 實(shí)現(xiàn)菜單從頂部彈出從底部消失動(dòng)畫效果

    SpringAnimation 實(shí)現(xiàn)菜單從頂部彈出從底部消失動(dòng)畫效果

    最近做項(xiàng)目遇到這樣一個(gè)需求,要求實(shí)現(xiàn)一種菜單,菜單從頂部彈入,然后從底部消失,頂部彈入時(shí),有一個(gè)上下抖動(dòng)的過程,底部消失時(shí),先向上滑動(dòng),然后再向下滑動(dòng)消失。下面給大家?guī)砹藢?shí)現(xiàn)代碼,感興趣的朋友一起看看吧
    2018-05-05
  • SpringBoot Jpa 自定義查詢實(shí)現(xiàn)代碼詳解

    SpringBoot Jpa 自定義查詢實(shí)現(xiàn)代碼詳解

    這篇文章主要介紹了SpringBoot Jpa 自定義查詢實(shí)現(xiàn)代碼詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java字節(jié)碼增強(qiáng)技術(shù)知識(shí)點(diǎn)詳解

    Java字節(jié)碼增強(qiáng)技術(shù)知識(shí)點(diǎn)詳解

    在本篇文章里小編給大家整理的是一篇關(guān)于Java字節(jié)碼增強(qiáng)技術(shù)知識(shí)點(diǎn)詳解內(nèi)容,有興趣的朋友可以跟著學(xué)習(xí)下。
    2021-08-08
  • Java網(wǎng)絡(luò)編程實(shí)現(xiàn)多線程聊天

    Java網(wǎng)絡(luò)編程實(shí)現(xiàn)多線程聊天

    這篇文章主要為大家詳細(xì)介紹了Java網(wǎng)絡(luò)編程實(shí)現(xiàn)多線程聊天,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • MyBatis的 config.xml標(biāo)簽

    MyBatis的 config.xml標(biāo)簽

    這篇文章主要介紹了MyBatis的 config.xml標(biāo)簽的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-12-12
  • Java實(shí)戰(zhàn)之用hutool-db實(shí)現(xiàn)多數(shù)據(jù)源配置

    Java實(shí)戰(zhàn)之用hutool-db實(shí)現(xiàn)多數(shù)據(jù)源配置

    在微服務(wù)搭建中經(jīng)常會(huì)使用到多數(shù)據(jù)庫情形這個(gè)時(shí)候,下面這篇文章主要給大家介紹了關(guān)于Java實(shí)戰(zhàn)之用hutool-db實(shí)現(xiàn)多數(shù)據(jù)源配置的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12

最新評(píng)論