首页 > 其他分享 >oidc-client.js踩坑吐槽贴

oidc-client.js踩坑吐槽贴

时间:2024-05-31 19:32:53浏览次数:20  
标签:code challenge js client PKCE oidc

前言

前面选用了IdentityServer4做为认证授权的基础框架,感兴趣的可以看上篇<微服务下认证授权框架的探讨>,已经初步完成了authorization-code与implicit的简易demo(html+js 在IIS部署的站点),并实现了SSO,本想着将Demo迁移到vue工程是轻而易举,毕竟也没啥东西,最终拿到access_token,存储到store里,跟传统的jwt基本上一样,不出意外,意外总是会发生,不然也没办法水一篇帖子,玩笑归玩笑,如果有理解错误,或者使用不当的地方,欢迎拍砖,以免误人子弟
image

环境角色

  • vue2.0 cli
  • .net core 6.0

这里为什么不用vue3,尝试过,最终放弃了,本来就是半吊子的前端水平,vue3里的vite跟ts,极大的增加了学习成本,包升级后一些莫名其妙的bug,特别是vite,一些bug提示对我来说特别陌生与不友好(项目不报错,js控制台报错,好像是兼容之类的问题),总之还是太菜,解决不了,又菜又爱玩
image

准备动手

在IdentityServer4里,对于前端工程提供了oidc-client.js这个包,在github开源,不过在2021年左右就停止维护了,这里我收集了两条跟本次吐槽相关的Issues
https://github.com/IdentityModel/oidc-client-js/issues/1393
https://github.com/IdentityModel/oidc-client-js/issues/1360

OAuth2.0 与 OAuth2.1

吓了一跳,OAuth2.1是个什么玩意?来看看GPT的回答
image
原来官方还没有这个东西,市面上一些对OAuth2.0拓展或者增强的东西,搞了个OAuth2.1,或许只是一个草案,本次吐槽的坑点就是oidc-client.js里PKCE的使用,PKCE全称是 Proof Key for Code Exchange, 在2015年发布, 它是 OAuth 2.0 核心的一个扩展协议, 所以可以和现有的授权模式结合使用,比如 Authorization Code + PKCE,东西是好东西,但是强制使用,不与之前的OAuth2.0兼容,就要被骂了
image

啥是PKCE?

大白话,就是防止授权码(code)被坏人拦截,而设计的一个拓展协议,坏人拿到了code也换取不了access_token,它的实现过程也非常简单,三两句就能讲明白,就不画图了,直接上代码截图
三个角色,授权服务,前端工程,后端工程

  1. 认证中心登录,回调页面上多了两个参数

code_challenge_method 签名方法
code_challenge 签名

  1. 使用code换取access_token的时候,要多带一个code_verifier(随机生成的一个字符串) 参数,否则兑换失败

code_challenge = code_challenge_method(code_verifier)

  1. 协议约定,如果在认证中心生成code的时候,携带了code_challenge_method与code_challenge,那么在使用code兑换
    access_token的时候,必须携带code_verifier

如果这还听不明白,那我举个古代银票防伪的例子
张三去钱庄存银子的时候,跟钱庄做了约定,留下一句暗号(DNF)跟暗号的生成方式(取每个字的首字符)给钱庄,兑换者在用银票换银子的时候,钱庄会检查这张银票有没有跟张三做约定,如果有约定,则按照约定让兑换者提供明文,钱庄用兑换者提供的明文跟张三提供的暗号生成方式,来生成暗号,如果一致则允许兑换银子
银票 = code
暗号 = 签名(code_challenge )
暗号的生成方式 = 签名方法(code_challenge_method )
明文 = code_verifier(随机字符串)

为啥要喷oidc-client.js里PKCE的实现?

  1. PKCE关不了
var config = {
    authority: "https://localhost:6201",
    ...
    pkce:false
};

前面Issues有提过,提供了这个配置,但是不生效,总之一定会带上

  1. 回调逻辑存在问题
var userManager = new Oidc.UserManager(config);
userManager.signinRedirectCallback().then(function(user) {
    // 登录成功,可以在这里处理登录后的逻辑,例如重定向到首页或显示欢迎信息
    console.log('用户已登录:', user);
    window.location.href = '/home'; // 重定向到应用的主页
}).catch(function(error) {
    // 处理登录失败的情况
    console.error('登录失败:', error);
    alert('登录过程中发生错误,请重试。');
});

image
image
这是oidc-client.js里回调页面的处理,它自动做了处理,但是它绕过后端程序,直接向认证服务发起,这里返回400错误,是因为该客户端必须校验秘钥,我们一般将秘钥存储在后端程序,前端程序请求后端,后端带上客户端秘钥,将请求转发给认证服务,这才是authorization-code标准的认证流程,也相对安全

  1. 相同的版本,在(html+js)站点下,并没有启用PKCE,而在vue-cli工程,默认启用PKCE

image
image
这点也是我最郁闷的地方,最开始我怀疑是版本问题导致的,后面我降级到相同的版本,但是结果却还是一样,折腾了好久,依旧没有解决,*******
image

解决办法

  1. 后端强行关闭PKCE认证

既然vue-cli工程里发起的获取code,会携带PKCE认证信息,那我在重定向地址里,把这两个参数移除,那就搞定收工了

  1. 啃oidc-client.js源码,翻Issues,看看有没有转机

先看Issues,把问题关键字贴进去搜一下,很遗憾没有找到有用的东西,源码简单的翻了下,也没啥帮助

  1. 逆向oidc-client.js,重写回调页面逻辑

既然我们缺code_verifier,那就去找,打印config.userStore,就找到了,这得感谢作者没有每次都删除该对象,不然可能就真的芭比Q了,知道了位置,我们直接从Localstorage取,然后根据时间戳取最新的那条记录,然后提取出code_verifier

function getCodeVerifier() {
  const allKeys = [];
  const items =[];
  for (let i = 0; i < localStorage.length; i++) {
    allKeys.push(localStorage.key(i));
  }
  const pattern = /^oidc\./;
  const oidcKeys = allKeys.filter(key => pattern.test(key));
  for(let i =0;i< oidcKeys.length;i++){
     const str = localStorage.getItem(oidcKeys[i]);
     if(str != null && str != ''){
      const model = JSON.parse(str);
      if(model.created == '' || model.created == null || model.created == undefined){
        continue
      }
      items.push(model)
      localStorage.removeItem(oidcKeys[i])
     }
  }
  const item = items.reduce((nearest, current) => {
    return (nearest.created > current.created) ? nearest : current;
  });
  return item.code_verifier;
}

最终效果

image

标签:code,challenge,js,client,PKCE,oidc
From: https://www.cnblogs.com/tibos/p/18225177

相关文章

  • 详解 JS 中的事件循环、宏/微任务、Primise对象、定时器函数,以及其在工作中的应用和注
    为什么会突然想到写这么一个大杂烩的博文呢,必须要从笔者几年前的一次面试说起当时的我年轻气盛,在简历上放了自己的博客地址,而面试官应该是翻了我的博客,好几道面试题都是围绕着我的博文来提问其中一个问题,直接使得空气静止了五分钟,然后面试官结束了这次面试,那就是:如何手写一个简......
  • const filePath = fileURLToPath(new URL('plopfile.js', import.meta.url)); 解释一
    这段代码的作用是获取当前文件所在目录下的plopfile.js文件的绝对路径。这里是逐步解释:import.meta.url:这是ESModules中的一个元属性,它提供了当前模块的绝对URL。在Node.js环境中,当你在一个模块文件中访问import.meta.url时,它会返回该模块文件的文件系统路径转换成的URL格......
  • nodejs判断文件、文件夹是否存在,不存在则创建
    方法解释ensureFileExistence(filePath):接受一个文件路径作为参数。使用path.dirname(filePath)获取文件目录路径。使用fs.existsSync和fs.mkdirSync确保目录存在。使用fs.existsSync和fs.writeFileSync确保文件存在。使用示例可以调用ensureFileExistenc......
  • (D卷,100分)- 约瑟夫问题(Java & JS & Python & C)
    获取题库不需要订阅专栏,可直接私信我进入CSDN领军人物top1博主的华为OD交流圈观看完整题库、最新面试实况、考试报告等内容以及大佬一对一答疑。题目描述输入一个由随机数组成的数列(数列中每个数均是大于0的整数,长度已知),和初始计数值m。从数列首位置开始计数,计数到m......
  • 【车间调度FJSP】基于全球邻域和爬山优化算法的模糊柔性车间调度问题研究(Matlab代码实
     ......
  • Chrom 如何禁用JS
    想复制网页上的文字,弹出需要登录等,很烦人。打开开发者工具按F12打开浏览器操作打开禁用JS运行命令按Ctrl+Shift+P或者如下图,鼠标点击,调出命令运行窗口在运行窗口中输入JavaScript点击停用,同理,再次点击,开启鼠标操作......
  • [JS零碎知识点01]Math内置对象
    一:Math数学对象Math 是一个内置对象,它拥有一些数学常数属性和数学函数方法。二:random()方法1 random()简介Math.random()为随机数函数,返回一个0到1之间随机小数数,并且包括0不包括1,[0,1)2随机数生成算法(1)生成0-10之间的随机整数Math.floor(Math.random()*11)推倒:Math......
  • vue 导出xlsx (报错./cptable in ./node modules/xlsx-style/dist/cpexcel.js)
    安装 xlsx 和  xlsx-stylesrc下创建文件夹utils, utils文件夹下创建index.js文件,index.js文件内容如下:*CreatedbyAnqion16/11/18.*//***Parsethetimetostring*@param{(Object|string|number)}time*@param{string}cFormat*@returns{stri......
  • 用.NET代码生成JSON Schema 验证器
    问题对于验证复杂JSON数据是否合法的需求,通常的解决方式是标准JSONSchema,.Net下有对应的JSONSchema实现库。应用程序通常需要将标准JSONschema传入实现库,来做后续的数据验证。这里有一种情况,就是如果使用者不太了解标准JSONSchema格式,但又希望能在自己的service中使用其强大......
  • 基于javaweb jsp ssm的停车场管理系统vue(源码+lw+部署文档+讲解等)
    前言......