文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题

2023-07-02 11:36

关注

这篇文章主要介绍“SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题”文章能帮助大家解决问题。

准备

spring-boot:2.1.4.RELEASE

spring-security-oauth3:2.3.3.RELEASE(如果要使用源码,不要随意改动这个版本号,因为2.4往上的写法不一样了)

mysql:5.7

效果展示

这边只用了postman做测试,暂时未使用前端页面来对接,下个版本角色菜单权限分配的会有页面的展示

访问开放接口http://localhost:7000/open/hello 

SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题

不带token访问受保护接口http://localhost:7000/admin/user/info

SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题

登录后获取token,带上token访问,成功返回了当前的登录用户信息

SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题

SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题

实现

oauth3一共有四种模式,这边就不做讲解了,网上搜一搜,千篇一律

因为现在只考虑做单方应用的,所以使用的是密码模式。

后面会出一篇SpringCloud+Oauth3的文章,网关鉴权

讲一下几个点吧

拦截器配置动态权限

SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题

新建一个 MySecurityFilter类,继承AbstractSecurityInterceptor,并实现Filter接口

初始化,自定义访问决策管理器

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

自定义 过滤器调用安全元数据源

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

先来看一下自定义过滤器调用安全元数据源的核心代码

以下代码是用来获取到当前请求进来所需要的权限(角色)

    @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<>();  //无需权限的,直接返回        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){   //默认权限的则只要登录了,无需权限匹配都可访问                    roleNames = new HashSet();                    break;                }                Map map = new HashMap();                map.put("resc_id", resc.getResc_id());                // 获取能访问该资源的所有权限(角色)                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("【所需的权限(角色)】:" + configAttributes);        return configAttributes;    }

再来看一下自定义访问决策管理器核心代码,这段代码主要是判断当前登录用户(当前登录用户所拥有的角色会在最后一项写到)是否拥有该权限角色

@Override    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {        if(configAttributes == null){   //属于白名单的,不需要权限            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())){   //有权限,可访问                    return;                }            }        }        throw new AccessDeniedException("没有权限访问");    }

自定义鉴权异常返回通用结果

为什么需要这个呢,如果不配置这个,对于前端,后端来说都很难去理解鉴权失败返回的内容,还不能统一解读,废话不多说,先看看不配置和配置了的返回情况

(1)未自定义前,没有携带token去访问受保护的API接口时,返回的结果是这样的

SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题

(2)我们规定一下,鉴权失败的接口返回接口之后,变成下面这种了,是不是更利于我们处理和提示用户

SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题

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

我们资源服务器OautyResourceConfig,重写下下面这部分的代码,来自定义鉴权异常返回的结果

大伙可以参考下这个https://www.yisu.com/article/131668.htm

@Override    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {        resources.authenticationEntryPoint(authenticationEntryPoint)    //token失效或没携带token时                .accessDeniedHandler(requestAccessDeniedHandler);   //权限不足时    }

SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题

获取当前登录用户

第一种:使用JWT携带用户信息,拿到token后再解析

暂不做解释

第二种:写一个SecurityUser实现UserDetails接口(这个工程中使用的是这一种)

原来的只有UserDetails接口只有username和password,这里我们加上我们系统中的User

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

在BaseController,每个Controller都会继承这个的,在里面写给getUser()的方法,只要用户带了token来访问,我们可以直接获取当前登录用户的信息了

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;    }

那么用户登录成功后,如何去拿到用户的角色集合等呢,这里面就要实现UserDetailsService接口了

SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题

@Servicepublic class TokenUserDetailsService implements UserDetailsService{    @Autowired    private LoginService loginService;    @Override    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {        User user = loginService.loadUserByUsername(username);  //这个我们拎出来处理        if(Objects.isNull(user))            throw new UsernameNotFoundException("用户名不存在");        return new SecurityUser(user);    }}

然后在我们的安全配置类中设置UserDetailsService为上面的我们自己写的就行

SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题

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

最后我们只需要在loginService里面实现我们的方法就好,根据我们的实际业务处理判断该用户是否存在等

@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));            //权限集合            Collection<? extends GrantedAuthority> authorities = merge(userRoles);            user.setAuthorities(authorities);            return user;        }        return null;    }

数据库文件在这

SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题

关于“SpringBoot怎么整合SpringSecurityOauth2实现鉴权动态权限问题”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网行业资讯频道,小编每天都会为大家更新不同的知识点。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯