Spring Security Oauth2 刷新token源码分析

2023-10-29

刷新token请求接口(/oauth/token)

参数:grant_type、refresh_token、client_id、client_secret
源码解析
1、grant_type为固定值:grant_type=refresh_token
在这里插入图片描述
源码中会根据grant_type是否为refresh_token且refresh_token字段不能为空来判断这个请求是刷新token还是获取token。

2、refresh_token是我们获取token时返回的一个字段用于刷新token
在这里插入图片描述
上图为oauth2.0返回token的字段其中包含refresh_token,我们只需要记住这个值,才有可能刷新token。
3、client_id和client_secret字段的获取
我们可以通过请求头的basic认证来从数据库中获取我们所需要的client_id和client_secret字段。
处理HTTP请求中的BASIC authorization头部,把认证结果写入SecurityContextHolder。
当一个HTTP请求中包含一个名字为Authorization的头部,并且其值格式是Basic xxx时,该Filter会认为这是一个BASIC authorization头部,其中xxx部分应该是一个base64编码的{username}:{password}字符串。比如用户名/密码分别为 admin/admin, 则对应的该头部是 : Basic XXXXXXX 。
该过滤器会从 HTTP BASIC authorization头部解析出相应的用户名和密码然后调用AuthenticationManager进行认证,成功的话会把认证了的结果写入到SecurityContextHolder中SecurityContext的属性authentication上面。同时还会做其他一些处理,比如Remember Me相关处理等等。
如果头部分析失败,该过滤器会抛出异常BadCredentialsException。
如果认证失败,则会清除SecurityContextHolder中的SecurityContext。并且不再继续filter chain的执行
org.springframework.security.web.authentication.www.BasicAuthenticationFilter类中处理过程

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        boolean debug = this.logger.isDebugEnabled();
        String header = request.getHeader("Authorization");
        if (header != null && header.toLowerCase().startsWith("basic ")) {
            try {
                String[] tokens = this.extractAndDecodeHeader(header, request);

                assert tokens.length == 2;

                String username = tokens[0];
                if (debug) {
                    this.logger.debug("Basic Authentication Authorization header found for user '" + username + "'");
                }

                if (this.authenticationIsRequired(username)) {
                    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, tokens[1]);
                    authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
                    Authentication authResult = this.authenticationManager.authenticate(authRequest);
                    if (debug) {
                        this.logger.debug("Authentication success: " + authResult);
                    }
					//此处将basic的认证结果存储到了Authentication。
                    SecurityContextHolder.getContext().setAuthentication(authResult);
                    this.rememberMeServices.loginSuccess(request, response, authResult);
                    this.onSuccessfulAuthentication(request, response, authResult);
                }
            } catch (AuthenticationException var10) {
                SecurityContextHolder.clearContext();
                if (debug) {
                    this.logger.debug("Authentication request for failed: " + var10);
                }

                this.rememberMeServices.loginFail(request, response);
                this.onUnsuccessfulAuthentication(request, response, var10);
                if (this.ignoreFailure) {
                    chain.doFilter(request, response);
                } else {
                    this.authenticationEntryPoint.commence(request, response, var10);
                }

                return;
            }

            chain.doFilter(request, response);
        } else {
            chain.doFilter(request, response);
        }
    }

紧接着我们继续看oauth2.0源码
org.springframework.security.oauth2.provider.endpoint.TokenEndpoint中这样写

 @RequestMapping(
        value = {"/oauth/token"},
        method = {RequestMethod.POST}
    )
    public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
    //这里我们将会用到basic认证所存储的对象Authentication
        if (!(principal instanceof Authentication)) {
            throw new InsufficientAuthenticationException("There is no client authentication. Try adding an appropriate authentication filter.");
        } else {
        //通过Authentication获取clientld
            String clientId = this.getClientId(principal);
            //ClientDetailsService可以通过jdbc连接数据库通过clientid查到我们需要的client_secret字段
            ClientDetails authenticatedClient = this.getClientDetailsService().loadClientByClientId(clientId);
            TokenRequest tokenRequest = this.getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
            if (clientId != null && !clientId.equals("") && !clientId.equals(tokenRequest.getClientId())) {
                throw new InvalidClientException("Given client ID does not match authenticated client");
            } else {
                if (authenticatedClient != null) {
                    this.oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
                }

                if (!StringUtils.hasText(tokenRequest.getGrantType())) {
                    throw new InvalidRequestException("Missing grant type");
                } else if (tokenRequest.getGrantType().equals("implicit")) {
                    throw new InvalidGrantException("Implicit grant type not supported from token endpoint");
                } else {
                    if (this.isAuthCodeRequest(parameters) && !tokenRequest.getScope().isEmpty()) {
                        this.logger.debug("Clearing scope of incoming token request");
                        tokenRequest.setScope(Collections.emptySet());
                    }

                    if (this.isRefreshTokenRequest(parameters)) {
                        tokenRequest.setScope(OAuth2Utils.parseParameterList((String)parameters.get("scope")));
                    }

                    OAuth2AccessToken token = this.getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);
                    if (token == null) {
                        throw new UnsupportedGrantTypeException("Unsupported grant type: " + tokenRequest.getGrantType());
                    } else {
                        return this.getResponse(token);
                    }
                }
            }
        }
    }

通过clientid获取ClientDetails

 public ClientDetails loadClientByClientId(String clientId) throws InvalidClientException {
        try {
            ClientDetails details = (ClientDetails)this.jdbcTemplate.queryForObject(this.selectClientDetailsSql, new JdbcClientDetailsService.ClientDetailsRowMapper(), new Object[]{clientId});
            return details;
        } catch (EmptyResultDataAccessException var4) {
            throw new NoSuchClientException("No client with requested id: " + clientId);
        }
    }

(源码中我加的注释不要错过哦)至此刷新token所需要的所有字段我们已经都聚齐了,此时只需要调用接口就可以刷新token了!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Security Oauth2 刷新token源码分析 的相关文章

随机推荐

  • VS2012创建ATL工程及使用MFC测试COM组件

    VS2012创建ATL工程及使用MFC测试COM组件 原创 2015年01月22日 16 23 21
  • 浏览器开发者模式F12的基本使用

    chrome浏览器的开发者工具可通过F12快捷键打开 1 调整开发者工具在页面的显示 2 检查界面元素 设备切换 网页或终端 终端选择 断点查看 3 可查看不同手机的界面适配问题 4 如何打断点 5 目标位置界面点击鼠标右键 检查 也可打开
  • ubuntu中conda安装pytorch 和 torch-geometric

    conda创建虚拟环境 conda create n pytorch python 3 7 conda activate pytorch 安装cuda nvidia smi 在这里插入图片描述 https img blog csdnimg
  • 铃木uy125最高时速_6K公里了谈谈轻骑铃木UY125的感受

    这也是很多人关心的 我以前是骑电驴的 电驴的动力弱 上坡无力这些都是常态 大排 公升的我没骑过 所以不谈 仅仅说下我的感受 转弯很灵活 我1米85的个子 极限转弯时 车把不会碰到膝盖 压弯不能太低 会蹭两侧的板子 离地间隙不高 比如上绿化带
  • Qt

    Qt 配置文件QSettings的使用方法 1 简介 配置文件常见的作用是启动软件是保留上次软件退出是的界面状态 如果不保留配置 且软件界面的内容又比较多 重启软件后界面恢复默认 那么每次打开界面都需要重新设置 这样比较麻烦 所以可以使用配
  • Qt中各种消息框对话框的使用

    在程序运行时 经常需要提示用户一些信息 比如警告啊 提示啊 建议啊之类的东西 这些东西基本上是通过消息框与用户进行交互的 Qt中主要是用QMessageBox类来加以实现的 消息框一般分为七种 Question询问消息框 为正常的操作提供一
  • 在小熊派BearPi-HM_Micro_small开发板上安装HAP

    引言 本文介绍如何在小熊派BearPi HM Micro small开发板上安装HAP 参考 https gitee com bearpi bearpi hm micro small blob master applications Bea
  • docker 非root用户修改mount到容器的文件出现“Operation not permitted

    使用环境centos7 x86 64 内核版本4 19 9 docker使用非root用户启动 daemon json配置文件内容如下 cat daemon json userns remap dockertest 映射的user和grou
  • UMG通过参数传递子弹个数给HUD

    今天 看UMG文档 发现无法传递 原因是应该传递到TEXT 而不是EditText 1 在firstpersonCharacter蓝图里 1 创建HUD 并保留HUD指针 2 发射时 子弹数 1 为0时不能发射 3 按R键 子弹数满 25
  • 逻辑回归梯度下降推导

    目录 什么是逻辑回归 逻辑回归的代价函数是怎么来的 逻辑回归求导 参考 什么是逻辑回归 逻辑回归 Logistic Regression 是用于处理因变量为分类变量的回归问题 常见的是二分类或二项分布问题 也可以处理多分类问题 它实际上是属
  • [c++11]多线程编程(五)——unique_lock

    c 11 多线程编程 五 unique lock 转自 https www jianshu com p 34d219380d90 互斥锁保证了线程间的同步 但是却将并行操作变成了串行操作 这对性能有很大的影响 所以我们要尽可能的减小锁定的区
  • el-table树形数据全部展开和收缩(toggleRowExpansion)

    本文主要讲根据element ui文档的toggleRowExpansion实现el table树形数据全部展开和收缩 1 页面效果 2 HTML页面展示 树形数据 直接使用element ui的demo数据 div div
  • Linux下特有的reboot()函数的简介

    1 Linux下c程序通过调用reboot 函数 可以实现系统的重启 挂机 Power Down等功能 2 1 对于libc5或libc4来说 库函数的原型声明中包含四个参数 具体函数原型声明如下 include
  • Linux内核浮点运算

    首次在linux内核驱动使用浮点型运算时出现了 undefined reference to aeabi uidiv 等错误 主要参考 Vedic的博客 toradexsh的博客 根据Vedic的博客修改makefile即可
  • vs2012编译boost_1_53_0

    Boost库的介绍 Boost库是一个经过千锤百炼 可移植 提供源代码的C 库 作为标准库的后备 是C 标准化进程的发动机之一 Boost库由C 标准委员会库工作组成员发起 其中有些内容有望成为下一代C 标准库内容 在C 社区中影响甚大 其
  • 数字签名MD4、MD5

    在本文中 模二加 记为 bigoplus 是二进制位的异或操作 如1模二加1和0模二加1都等于0 1模二加0等于1 模 2 32
  • 对机器进行免密之后还是不能免密登录

    查看远程机器的 var log secure日志 有以下错误 Authentication refused bad ownership or modes for directory home loanusr ssh Authenticati
  • Dynamics CRM2013 Lookup Filtering using addCustomFilter

    dynamics crm中对lookup视图的过滤是一个很平常性的需求 在2011的时候都是用添加自定义视图的方式例如下面这段示例代码 span style font size 18px var pEntityName sc stock v
  • Rust学习资料

    Installing Rust Rustup the Rust installer and version management tool Windows Subsystem for Linux Cargo the Rust build t
  • Spring Security Oauth2 刷新token源码分析

    刷新token请求接口 oauth token 参数 grant type refresh token client id client secret 源码解析 1 grant type为固定值 grant type refresh tok