0

0

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

王林

王林

发布时间:2023-05-11 10:28:05

|

1758人浏览过

|

来源于亿速云

转载

准备

spring-boot:2.1.4.release

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

mysql:5.7

效果展示

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

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

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

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

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

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

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

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

实现

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

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

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

讲一下几个点吧

1、拦截器配置动态权限

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

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

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

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

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

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

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

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

/**
     * 获得当前请求所需要的角色
     * @param object
     * @return
     * @throws IllegalArgumentException
     */
    @Override
    public Collection 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 list = new ArrayList<>();  //无需权限的,直接返回
        list.add("/oauth/**");
        list.add("/open/**");
        if(matcher.pathsMatchesUrl(list,requestUrl))
            return null;

        Set 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 roles = roleRescMapper.findAll(map);
                for (RoleRescDTO rr : roles)
                    roleNames.add(rr.getRole_name());
            }
        }

        Set 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 configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        if(configAttributes == null){   //属于白名单的,不需要权限
            return;
        }
        Iterator 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("没有权限访问");

    }

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

koly.club
koly.club

一站式社群管理工具

下载

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

(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实现鉴权动态权限问题

3、获取当前登录用户

第一种:使用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实现鉴权动态权限问题

@Service
public 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 userRoles = userRoleMapper.findAll(map);
            user.setRoles(listRoles(userRoles));
            //权限集合
            Collection authorities = merge(userRoles);
            user.setAuthorities(authorities);
            return user;
        }
        return null;

    }

数据库文件在这

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

相关专题

更多
C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

10

2026.01.23

php远程文件教程合集
php远程文件教程合集

本专题整合了php远程文件相关教程,阅读专题下面的文章了解更多详细内容。

29

2026.01.22

PHP后端开发相关内容汇总
PHP后端开发相关内容汇总

本专题整合了PHP后端开发相关内容,阅读专题下面的文章了解更多详细内容。

21

2026.01.22

php会话教程合集
php会话教程合集

本专题整合了php会话教程相关合集,阅读专题下面的文章了解更多详细内容。

21

2026.01.22

宝塔PHP8.4相关教程汇总
宝塔PHP8.4相关教程汇总

本专题整合了宝塔PHP8.4相关教程,阅读专题下面的文章了解更多详细内容。

13

2026.01.22

PHP特殊符号教程合集
PHP特殊符号教程合集

本专题整合了PHP特殊符号相关处理方法,阅读专题下面的文章了解更多详细内容。

11

2026.01.22

PHP探针相关教程合集
PHP探针相关教程合集

本专题整合了PHP探针相关教程,阅读专题下面的文章了解更多详细内容。

8

2026.01.22

菜鸟裹裹入口以及教程汇总
菜鸟裹裹入口以及教程汇总

本专题整合了菜鸟裹裹入口地址及教程分享,阅读专题下面的文章了解更多详细内容。

55

2026.01.22

Golang 性能分析与pprof调优实战
Golang 性能分析与pprof调优实战

本专题系统讲解 Golang 应用的性能分析与调优方法,重点覆盖 pprof 的使用方式,包括 CPU、内存、阻塞与 goroutine 分析,火焰图解读,常见性能瓶颈定位思路,以及在真实项目中进行针对性优化的实践技巧。通过案例讲解,帮助开发者掌握 用数据驱动的方式持续提升 Go 程序性能与稳定性。

9

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Spring中文手册
Spring中文手册

共0课时 | 0人学习

马士兵spring视频教程
马士兵spring视频教程

共25课时 | 9.1万人学习

Redis6入门到精通超详细教程
Redis6入门到精通超详细教程

共47课时 | 5.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号