首页 文章 精选 留言 我的

精选列表

搜索[分库分表],共10000篇文章
优秀的个人博客,低调大师

5分钟搞懂分布式基础概念

分布式基础概念 1、微服务 拒绝大型单体应用,基于业务边界进行服务微化拆分,各个服务独立部署运行 2、集群、分布式、节点 集群 是一种物理形态 将几台服务器集中在一起,实现同一业务 分布式 是一种工作方式 若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统 将不同的业务分布在不同的地方 节点 集群中的一个服务器 3、远程调用 分布式系统中,各个服务可能处于不同主机,但是服务之间不可避免的需要互相调用,我们称为远程调用。 SpringCloud中使用HTTP+JSON的方式完成远程调用。 4、负载均衡 A服务调用B服务,B服务部署在多台机器,A发送请求到任意一个服务器均可完成调用。 为了使每台服务器不至于忙于处理请求,可以将请求均衡到每一个服务器,提升网站的可用性。 负载均衡算法: 轮询:请求依次按顺序分发到不同的可用服务器执行,循环分发请求。 最小连接:分发请求到连接数最少的服务器。场景:处理请求用时较长的场景。 散列:根据用户请求的IP地址的散列(hash)来选择要转发的服务器。场景:需要处理状态而要求用户能连接到相同服务器。 5、服务注册、服务发现、注册中心 A服务调用B服务、C服务,但是A服务不知道B、C服务所在的服务器是正常还是下线,注册中心可以帮助解决。 注册中心实时知道哪些服务正常,哪些服务下线,也能记录新增的正常服务。服务之间调用不需要去判断哪些服务正常,注册中心会告诉服务有效的调用地址。 服务注册:服务将自己的IP和端口报告给注册中心的过程。 服务发现:查询可用微服务列表及其网络地址的机制。 注册中心:集中记录每个服务的地址,注册和注销服务。 服务检查:检查已注册的服务,如发现某服务长时间无法访问,则会从注册中心移除该服务。 6、配置中心 每个服务都有大量配置,更新一个配置,需要同步到每个服务,如何修改每个服务的配置呢? 每个服务从配置中心获取配置,自动更新自己的配置。 7、服务熔断、服务降级 mark 下单场景:用户下单了一个商品,客户端调用订单服务来生成预付款订单,订单服务调用商品服务查看下单的哪款商品,商品服务调用库存服务判断这款商品是否有库存,如有库存,则可以生成预付款订单。 雪崩场景: 第一次滚雪球:库存服务不可用(如响应超时等),库存服务收到的很多请求都未处理完,库存服务将无法处理更多请求。 第二次滚雪球:因商品服务的请求都在等库存服务返回结果,导致商品服务调用库存服务的很多请求未处理完,商品服务将无法处理其他请求,导致商品服务不可用 第三次滚雪球:因商品服务不可用,订单服务调用商品服务的的其他请求无法处理,导致订单服务不可用。 第四次滚雪球:因订单服务不可用,客户端将不能下单,更多客户将重试下单,将导致更多下单请求不可用。 服务熔断: 设置服务的超时,当被调用的服务某段时间内失败率达到某个阈值,则对该服务开启短路保护,后来的请求不调用这个服务,直接返回默认的数据。 服务降级: 对非核心业务降级运行:某些服务不处理,或者简单处理(抛异常、返回Null、返回Mock数据) 8、API网关 抽象了微服务中都需要的公共功能 提供了负载均衡、自动熔断、灰度发布、统一认证、限流、日志统计功能 本文分享自微信公众号 - 悟空聊架构(PassJava666)。 如有侵权,请联系 support@oschina.cn 删除。 本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

WorkPlus Lite 10分钟快速上手指南

跟随笔者一步一步来了解如何体验与开始使用WorkPlus Lite 1. 试用在线版本 我们建议您从体验WorkPlus Lite的在线版本开始,以了解WorkPlus Lite的强大功能。您可以下载与使用我们的官方版本。 扫描二维码 或直接点击下载 官网下载 下载完成后,按照App提示,使用您的手机号注册一个新帐号,您就可以开始体验我们的在线版本了。 2. 部署私有版本 如果您对WorkPlus Lite感兴趣,现在开始,您可以开始尝试部署一个只属于自己的私有版本。 2.1 了解不同版本 WorkPlus Lite提供了开源社区版以及开源授权版两个版本。我们希望您先了解它们之间的差别。访问版本对比以了解更多 开源社区版是完全开源免费的. 2.2 部署与安装后台 WorkPlus Lite开源版的后台当前支持以Docker的方式单机部署,后续会增加集群版方式部署的支持 2.2.1 安装 部署后台非常简单,只需一行代码 /bin/bash -c "$(curl -fsSL https://lite.workplus.io/install.sh)" 查阅详细部署文档 2.2.2 初始化 在提示安装完成后,您可以使用 http://yourip:9000/ 来访问后台管理界面,在这个过程中,会有一个初始化的过程. 初始化 **免费License说明** 安装完成后,第一次需要初始化,初始化会向WorkPlus官方申请到一个免费的License. License只在第一次初始化时会向WorkPlus自动申请。 基于此License您将获取***开源社区版***的所有功能与服务。 初始化,需要填写一些手机号,创建新的域及组织 完成后,可以使用初始化过程中您设置的用户名密码,登录域或组织管理后台。 2.3 部署移动端 部署好后台服务后,您可以开始部署移动端了。您有三种方式来部署您的移动端。 2.3.1 使用我们的在线版本 如果您不想大费周章,您可以选择使用我们的在线版本做为您的客户端,这是最简单快速的一种方式。 我们已经为您做好了所有准备,您唯一需要做的是使用我们的在线版本扫码绑定自己的企业就可。 访问管理后台 http://yourip:9000/ 页面上会列出如上图您部署的版本的企业二维码 打开App登录页,选择扫码绑定新企业功能 2.3.2 基于源码构建 当然,您也可以选择基于源码来构建您的App,这将给您带来极大的自由。 您可以随心所欲的按照您的想法来构建您自己的App。 客户端(含iOS及Android两端)是基于MIT协议完全开源的。 访问我们的开源主页以了解更多。 同时,访问我们的接入与指引以了解如何编译运行我们的源码 2.3.3 专业定制支持 如果您希望构建属于自己的特别的App,但又缺少对应的技术能力。您可以考虑由WorkPlus Lite团队提供的专业服务。 WorkPlus Lite团队支持提供个性化定制服务,包括为您构建客户端等。 申请专业定制 也可以通过 lite@foreverht.com 联系我们申请 3. 业务扩展与开发 如果一切顺利,您将得到一个自己的移动平台,这一切如此轻松简单。 这就是我们WorkPlus Lite致力于为您带来的服务与体验。 但这不是终点,这只是一个开始。WorkPlus Lite更强大的功能在于它强大的业务扩展能力,基于这些强大的扩展能力,它使我们的WorkPlus Lite成为一个平台而非简单的App. WorkPlus Lite提供了Api接入,服务号,轻应用,工作台以及ISV生态等多种业务扩展能力。您可以选择最合适的方式来定制您的业务。 3.1 Api接入 您可以访问我们的 Api接入 文档以了解如何开始接入我们的Api。 通过Api我们提供了用户,雇员,组织,媒体,应用,消息等Api,您可以选择通过这些Api方便的与您现有的业务进行整合 3.2 服务号 类似于微信的服务号功能,支持菜单定制,自动回复,关键词回复,更支持开发模式,让您的业务通过服务号一键到达用户。 您可以在管理后台,新建服务号,并配置服务号的菜单,回复等。 更进一步,您可以选择服务号的开发者模式,这种模式支持将用户的输入的内容传入给一个第三方系统,第三方系统根据业务处理完成再回复给用户。 3.3 轻应用 您可以选择将您的业务以H5的方式,成为WorkPlus Lite中的一个应用。这为您的业务带来了更多的可能性。 为有效的支撑H5方式的业务开发,WorkPlus Lite提供了Cordova机制,H5可以方便的使用Cordova调用原生能力,如获取当前用户信息,处理图片,单点登录等. 访问我们的Cordova 文档以了解如何开始接入我们的Cordova。 3.4 工作台 我们提供了十多种丰富的工作台的卡片,包含广告卡片,新闻卡片,搜索卡片,自定义卡片等。 通过工作台卡片机制,您只需要返回数据,我们就能以卡片的方式展现您的业务。 访问工作台 以开始您自己的工作台开发工作 3.5. ISV生态 我们提供了更为强大的ISV生态能力,在为大型企业服务的数年经验及在其基础之上的孵化的一些应用:移动考勤,表单,流程大师等,都放在ISV上,您可以直接从管理后台中添加购买这些然后立刻使用它们。 如果您有自己的应用并希望加入我们的ISV生态,被更广泛的使用,请联系我们。 4. 联系我们 感谢您对WorkPlus Lite的关注与使用,如果您在使用的过程中遇到任何问题,都可以通过以下几种方式反馈或与我们联系,我们将竭诚为您服务。 如果您发现Bug,请到我们的开源主页提交Issues. 产品团队会尽快修复相关Bug. 如果您在使用或开发过程中遇到问题无法解决,可以发送邮件至 lite@foreverht.com. 如果您有其它疑问或沟通需求,请通过微信,添加我们的企业帐号联系我们. 联系我们

优秀的个人博客,低调大师

10分钟彻底搞懂单页面应用路由

上一次,跟大家科普了小程序的自定义路由routes,开启了路由之旅;今天,顺势就单页面应用路由,跟大家唠个五毛钱,如果唠得不好……退…一块钱? 单页面应用特征 假设: 在一个 web 页面中,有1个按钮,点击可跳转到站内其他页面。 多页面应用: 点击按钮,会从新加载一个html资源,刷新整个页面; 单页面应用: 点击按钮,没有新的html请求,只发生局部刷新,能营造出一种接近原生的体验,如丝般顺滑。 SPA 单页面应用为什么可以几乎无刷新呢?因为它的SP——single-page。在第一次进入应用时,即返回了唯一的html页面和它的公共静态资源,后续的所谓“跳转”,都不再从服务端拿html文件,只是DOM的替换操作,是模(jia)拟(zhuang)的。 那么js又是怎么捕捉到组件切换的时机,并且无刷新变更浏览器url呢?靠hash和HTML5History。 hash 路由 特征 类似www.xiaoming.html#bar 就是哈希路由,当 # 后面的哈希值发生变化时,不会向服务器请求数据,可以通过 hashchange 事件来监听到 URL 的变化,从而进行DOM操作来模拟页面跳转 不需要服务端配合 对 SEO 不友好 原理 HTML5History 路由 特征 History 模式是 HTML5 新推出的功能,比之 hash 路由的方式直观,长成类似这个样子www.xiaoming.html/bar ,模拟页面跳转是通过 history.pushState(state, title, url) 来更新浏览器路由,路由变化时监听 popstate 事件来操作DOM 需要后端配合,进行重定向 对 SEO 相对友好 原理 vue-router 源码解读 以 Vue 的路由vue-router为例,我们一起来撸一把它的源码。 Tips:因为,本篇的重点在于讲解单页面路由的两种模式,所以,下面只列举了一些关键代码,主要讲解: 注册插件 VueRouter的构造函数,区分路由模式 全局注册组件 hash / HTML5History模式的 push 和监听方法 transitionTo 方法 注册插件 首先,作为一个插件,要有暴露一个install方法的自觉,给Vue爸爸去 use。 源码的install.js文件中,定义了注册安装插件的方法install,给每个组件的钩子函数混入方法,并在beforeCreate钩子执行时初始化路由: Vue.mixin({ beforeCreate () { if (isDef(this.$options.router)) { this._routerRoot = this this._router = this.$options.router this._router.init(this) Vue.util.defineReactive(this, '_route', this._router.history.current) } else { this._routerRoot = (this.$parent && this.$parent._routerRoot) || this } registerInstance(this, this) }, // 全文中以...来表示省略的方法 ... }); 区分mode 然后,我们从index.js找到整个插件的基类 VueRouter,不难看出,它是在constructor中,根据不同mode 采用不同路由实例的。 ... import {install} from './install'; import {HashHistory} from './history/hash'; import {HTML5History} from './history/html5'; ... export default class VueRouter { static install: () => void; constructor (options: RouterOptions = {}) { if (this.fallback) { mode = 'hash' } if (!inBrowser) { mode = 'abstract' } this.mode = mode switch (mode) { case 'history': this.history = new HTML5History(this, options.base) break case 'hash': this.history = new HashHistory(this, options.base, this.fallback) break case 'abstract': this.history = new AbstractHistory(this, options.base) break default: if (process.env.NODE_ENV !== 'production') { assert(false, `invalid mode: ${mode}`) } } } } 全局注册router-link组件 这个时候,我们也许会问:使用 vue-router 时, 常见的<router-link/>、 <router-view/>又是在哪里引入的呢? 回到install.js文件,它引入并全局注册了 router-view、router-link组件: import View from './components/view'; import Link from './components/link'; ... Vue.component('RouterView', View); Vue.component('RouterLink', Link); 在 ./components/link.js 中,<router-link/>组件上默认绑定了click事件,点击触发handler方法进行相应的路由操作。 const handler = e => { if (guardEvent(e)) { if (this.replace) { router.replace(location, noop) } else { router.push(location, noop) } } }; 就像最开始提到的,VueRouter构造函数中对不同mode初始化了不同模式的 History 实例,因而router.replace、router.push的方式也不尽相同。接下来,我们分别扒拉下这两个模式的源码。 hash模式 history/hash.js 文件中,定义了HashHistory 类,这货继承自 history/base.js 的 History 基类。 它的prototype上定义了push方法:在支持 HTML5History 模式的浏览器环境中(supportsPushState为 true),调用history.pushState来改变浏览器地址;其他浏览器环境中,则会直接用location.hash = path 来替换成新的 hash 地址。 其实最开始读到这里是有些疑问的,既然已经是 hash 模式为何还要判断supportsPushState?是为了支持scrollBehavior,history.pushState可以传参key过去,这样每个url历史都有一个key,用 key 保存了每个路由的位置信息。 同时,原型上绑定的setupListeners 方法,负责监听 hash 变更的时机:在支持 HTML5History 模式的浏览器环境中,监听popstate事件;而其他浏览器中,则监听hashchange。监听到变化后,触发handleRoutingEvent 方法,调用父类的transitionTo跳转逻辑,进行 DOM 的替换操作。 import { pushState, replaceState, supportsPushState } from '../util/push-state' ... export class HashHistory extends History { setupListeners () { ... const handleRoutingEvent = () => { const current = this.current if (!ensureSlash()) { return } // transitionTo调用的父类History下的跳转方法,跳转后路径会进行hash化 this.transitionTo(getHash(), route => { if (supportsScroll) { handleScroll(this.router, route, current, true) } if (!supportsPushState) { replaceHash(route.fullPath) } }) } const eventType = supportsPushState ? 'popstate' : 'hashchange' window.addEventListener( eventType, handleRoutingEvent ) this.listeners.push(() => { window.removeEventListener(eventType, handleRoutingEvent) }) } push (location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this this.transitionTo( location, route => { pushHash(route.fullPath) handleScroll(this.router, route, fromRoute, false) onComplete && onComplete(route) }, onAbort ) } } ... // 处理传入path成hash形式的URL function getUrl (path) { const href = window.location.href const i = href.indexOf('#') const base = i >= 0 ? href.slice(0, i) : href return `${base}#${path}` } ... // 替换hash function pushHash (path) { if (supportsPushState) { pushState(getUrl(path)) } else { window.location.hash = path } } // util/push-state.js文件中的方法 export const supportsPushState = inBrowser && (function () { const ua = window.navigator.userAgent if ( (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) && ua.indexOf('Mobile Safari') !== -1 && ua.indexOf('Chrome') === -1 && ua.indexOf('Windows Phone') === -1 ) { return false } return window.history && typeof window.history.pushState === 'function' })() HTML5History模式 类似的,HTML5History 类定义在 history/html5.js 中。 定义push原型方法,调用history.pusheState修改浏览器的路径。 与此同时,原型setupListeners 方法对popstate进行了事件监听,适时做 DOM 替换。 import {pushState, replaceState, supportsPushState} from '../util/push-state'; ... export class HTML5History extends History { setupListeners () { const handleRoutingEvent = () => { const current = this.current; const location = getLocation(this.base); if (this.current === START && location === this._startLocation) { return } this.transitionTo(location, route => { if (supportsScroll) { handleScroll(router, route, current, true) } }) } window.addEventListener('popstate', handleRoutingEvent) this.listeners.push(() => { window.removeEventListener('popstate', handleRoutingEvent) }) } push (location: RawLocation, onComplete?: Function, onAbort?: Function) { const { current: fromRoute } = this this.transitionTo(location, route => { pushState(cleanPath(this.base + route.fullPath)) handleScroll(this.router, route, fromRoute, false) onComplete && onComplete(route) }, onAbort) } } ... // util/push-state.js文件中的方法 export function pushState (url?: string, replace?: boolean) { saveScrollPosition() const history = window.history try { if (replace) { const stateCopy = extend({}, history.state) stateCopy.key = getStateKey() history.replaceState(stateCopy, '', url) } else { history.pushState({ key: setStateKey(genStateKey()) }, '', url) } } catch (e) { window.location[replace ? 'replace' : 'assign'](url) } } transitionTo 处理路由变更逻辑 上面提到的两种路由模式,都在监听时触发了this.transitionTo,这到底是个啥呢?它其实是定义在 history/base.js 基类上的原型方法,用来处理路由的变更逻辑。 先通过const route = this.router.match(location, this.current)对传入的值与当前值进行对比,返回相应的路由对象;接着判断新路由是否与当前路由相同,相同的话直接返回;不相同,则在this.confirmTransition中执行回调更新路由对象,并对视图相关DOM进行替换操作。 export class History { ... transitionTo ( location: RawLocation, onComplete?: Function, onAbort?: Function ) { const route = this.router.match(location, this.current) this.confirmTransition( route, () => { const prev = this.current this.updateRoute(route) onComplete && onComplete(route) this.ensureURL() this.router.afterHooks.forEach(hook => { hook && hook(route, prev) }) if (!this.ready) { this.ready = true this.readyCbs.forEach(cb => { cb(route) }) } }, err => { if (onAbort) { onAbort(err) } if (err && !this.ready) { this.ready = true // https://github.com/vuejs/vue-router/issues/3225 if (!isRouterError(err, NavigationFailureType.redirected)) { this.readyErrorCbs.forEach(cb => { cb(err) }) } else { this.readyCbs.forEach(cb => { cb(route) }) } } } ) } ... } 最后 好啦,以上就是单页面路由的一些小知识,希望我们能一起从入门到永不放弃~~

优秀的个人博客,低调大师

一分钟快速了解边缘计算

无论IT端还是OT端的主流厂商都将目光聚焦在了“边缘计算”这个焦点上,边缘计算(Edge computing)是相对云计算而言的,它是指收集并分析数据的行为发生在靠近数据生成的本地设备和网络中。边缘计算又被叫做分布式云计算、雾计算或第四代数据中心。 1、什么是边缘计算 边缘计算是接近事物,或者将是在数据和行动源头进行的,更靠近设备端和用户。像一只八爪鱼,有两个强大的记忆系统:云计算是大脑记忆系统,边缘计算是八个爪子上的吸盘。也就是说,云计算就像章鱼大脑只有一个,而边缘计算有八条腿可以思考并解决问题,一个爪子就是一个小型机房,靠近具体实物。 2、为什么需要边缘计算 到2020年,互联网会有500亿用户,每天产生大约几PB的数据,如果这些数据直接上传数据中心进行处理,不仅会浪费巨大的网络带宽,也会给存储带来负担。如果有了边缘计算,那么别人还在加载不出来,你缺已经下载完一部几百兆电影,就很快乐。所以也可以说,边缘计算和5G是相辅相成。 3、边缘计算应用场景 边缘计算在物联网时代不断增长的数据催生了需求,边缘计算的典型应用场景有:工业制造、安全监控、ARVR、智能交通、自动驾驶、智慧家居、智慧城市、智慧路灯、风力发电、医疗保健、无人机等。

优秀的个人博客,低调大师

【远程办公】5分钟学会搭建内网穿透

疫情期间大家都在讨论 远程办公的实现,推荐看下黄东旭大佬 写的 《PingCAP的5年远程办公实践》,以下内网映射工具作为常用补充。 来讲讲为啥要做内网映射 从公网中访问自己的内网设备一直是个麻烦事情,尤其是做微信开发等。设备可能处于路由器后,或者运营商因为IP地址短缺不给你分配公网IP地址。如果我们想直接访问到这些设备,一般非常麻烦。 求网管大佬在路由器上给自己内网加个端口映射 购买 花生壳 等动态域名解析软件 使用 natapp 等免费(也有付费的)的提供的内网映射服务 基于ngrok/frp自建内网映射服务 为什么放弃 ngrok,使用 frp 我们在2016年提供了一个ngrok 的免费服务,并且分享了搭建的步骤可以参考《Angrok 一个内网穿透服务》 ,搭建步骤对于一般的用户非常不友好,后边也就停止了相关的服务转向了 frp。 Github 的关注度对比 穿透协议支持 frp 支持 http ssh tcp udp ftp 等协议 开始动手 准备工作 搭建一个完整的frp服务,我们需要 公网IP 的 ECS 一台 域名 (若不需要解析则不需要) 安装 frp (frps)服务端 下载 frp 安装包 https://github.com/fatedier/frp/releases/download/v0.31.1/frp_0.31.1_darwin_amd64.tar.gz 解压压缩包,修改 frps.ini [common] bind_port = 7000 # frps 服务启动,占用的端口 vhost_http_port = 80 # frps 服务监听转发的端口 启动 frps 服务 ./frps -c ./frps.ini 安装 frp(frpc)客户端 在目标内网设备机器,安装客户端。 根据操作系统下载不同版本 自定义域名访问内网服务 修改 frpc.ini [common] server_addr = ECS的公网IP server_port = 7000 [随意但必须唯一] type = http local_port = 本地目标服务的端口 custom_domains = 自定义的域名 启动客户端 ./frpc -c ./frpc.ini 访问 自定义域名即可访问内网的服务 使用ssh访问公司内网机器 修改 frpc.ini [common] server_port = 7000 [随意但必须唯一] type = tcp local_ip = 127.0.0.1 local_port = 22 remote_port = 10022 启动客户端 ./frpc -c ./frpc.ini 通过 ssh 访问内网机器 ssh -p 10022 root@x.x.x.x

优秀的个人博客,低调大师

用 Authing 10分钟实现单点登录(SSO)

单点登录(Single Sign On),简称为SSO,是目前比较流行的企业业务整合的解决方案之一。 SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。 实现单点登录 开始之前 如果你不了解用户池、单点登录和认证授权,建议先阅读基础概念。 预备知识 基本的 HTML 和 CSS 知识 中级 JavaScript 技能 所需工具 你喜欢的文本编辑器 可以在本地运行的 Web 服务器(比如:npm install http-server -g) 注册一个 Authing 账号 如果你还没有账号,请点击这里注册 Authing 账号,注册完成后请进入控制台并创建一个用户池。 创建一个 OIDC 应用 第三方登录 -> OIDC 应用选项卡,点击蓝色的「创建 OIDC 应用」按钮。 填上你的应用名,指定此 OIDC 应用的二级域名(认证地址),回调地址,其他参数保留默认即可。点击「确定」。 参数解释 认证地址,一个 authing.cn 的二级域名,用户将在此网址进行登录。 回调 URL,OIDC 登录成功后,回调到开发者自己业务的地址。本教程为演示,填写的地址是 http://localhost:8080,实际场景下要填写自己的业务地址。 在应用列表中点击刚创建好的应用,记录下 AppID,二级域名,供以后使用。 使用 AuthingSSO SDK 集成单点登录 创建一个空白的 HTML 文档用来编写 Authing 程序 本教程只是为了演示,因此我们没选择高级框架,这可以让我们专注于 Authing 本身。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Authing SSO Example</title> </head> <body></body> </html> 添加三个按钮 增加三个按钮控件到 body 中,目的是为了演示如何使用 SDK 管理单点登录状态。 <button id="btn-login">login</button> <button id="btn-track-session">trackSession</button> <button id="btn-logout">logout</button> 引入 AuthingSSO 并初始化 从 CDN 加载 AuthingSSO 的 SDK。填入你的 OIDC 应用 ID 和 域名,进行初始化。 <script src="https://cdn.jsdelivr.net/npm/@authing/sso/dist/AuthingSSO.umd.min.js"></script> <script> let auth = new AuthingSSO({ appId: "YOUR_OIDC_APP_ID", appType: "oidc", appDomain: "OIDC_APP_DOMAIN.authing.cn" }); </script> 为按钮注册点击事件 达到的效果是: 点击 login 按钮,浏览器会跳转到 OIDC 登录页面,与用户完成身份确认。 点击 trackSession 按钮,会显示当前登录状态。 点击 logout 按钮,进行单点登出。 let login = document.getElementById("btn-login"); let trackSession = document.getElementById("btn-track-session"); let logout = document.getElementById("btn-logout"); login.onclick = function() { auth.login(); }; trackSession.onclick = async function() { let res = await auth.trackSession(); alert(JSON.stringify(res)); }; logout.onclick = async function() { let res = await auth.logout(); alert(JSON.stringify(res)); }; 完整代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Authing SSO Example</title> </head> <body> <button id="btn-login">login</button> <button id="btn-track-session">trackSession</button> <button id="btn-logout">logout</button> <script src="https://cdn.jsdelivr.net/npm/@authing/sso/dist/AuthingSSO.umd.min.js"></script> <script> let auth = new AuthingSSO({ appId: "YOUR_OIDC_APP_ID", appType: "oidc", appDomain: "OIDC_APP_DOMAIN.authing.cn" }); let login = document.getElementById("btn-login"); let trackSession = document.getElementById("btn-track-session"); let logout = document.getElementById("btn-logout"); login.onclick = function() { auth.login(); }; trackSession.onclick = async function() { let res = await auth.trackSession(); alert(JSON.stringify(res)); }; logout.onclick = async function() { let res = await auth.logout(); alert(JSON.stringify(res)); }; </script> </body> </html> 示例代码可从 Github 上找到,建议将 Github 上的代码下载运行。 运行方法 在终端中运行以下命令 $ git clone https://github.com/Authing/authing-sso-demo $ cd authing-sso-demo $ npm install -g http-server $ http-server 之后在浏览器访问 http://localhost:8080。 {% hint style="warning" %} 如果本地 8080 端口已被占用,应用可能会运行在 8081、8082 等后续端口。 {% endhint %} 运行效果 最初,我们没有登录,因此,点击 trackSession 按钮获取到的登录状态为空。 现在我们点击 login 按钮,会跳转到 OIDC 应用的用户认证页面,输入用户名密码进行登录。 浏览器被重定向到我们之前设置的回调链接,记下 code 参数,用于后面换取用户信息。 点击 trackSession 按钮,此时能够获取到该用户的登录状态,包括用户 ID,应用 ID,应用类型。 点击 logout 按钮,输出单点登出成功。 此时我们再点击 trackSession 按钮,可见登录状态为空,说明用户已经单点登出了。 获取用户信息 使用 OIDC 流程中返回的 code 换取 access_token 向以下地址发送 POST 请求: POST https://OIDC_APP_DOMAIN.authing.cn/oauth/oidc/token body 参数 参数名 意义 client_id OIDC 应用的 app_id redirect_uri 在控制台配置的 OIDC 回调 url 其中的一个值 scope 需要请求的权限,如果需要获取 email 和手机号需要有 phone email,如果需要 refresh_token 需要包含 offline_access 参考 scope 表格 response_type OIDC 模式,可以为 code, id_token, id_token token, code id_token, code token, code id_token token 参考 OIDC 规范 prompt 可以为 none,login,consent 或 select_account,指定 AP 与 End-User 的交互方式,如需 refresh_token,必须为 consent 参考 OIDC 规范 state 一个随机字符串,用于防范 CSRF 攻击,如果 response 中的 state 值和发送请求之前设置的 state 值不同,说明受到攻击 nonce 一个随机字符串,用于防范 Replay 攻击 返回示例 { "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJqdGkiOiJ4R01uczd5cmNFckxiakNRVW9US1MiLCJzdWIiOiI1YzlmNzVjN2NjZjg3YjA1YTkyMWU5YjAiLCJpc3MiOiJodHRwczovL2F1dGhpbmcuY24iLCJpYXQiOjE1NTQ1Mzc4NjksImV4cCI6MTU1NDU0MTQ2OSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBvZmZsaW5lX2FjY2VzcyBwaG9uZSBlbWFpbCIsImF1ZCI6IjVjYTc2NWUzOTMxOTRkNTg5MWRiMTkyNyJ9.wX05OAgYuXeYM7zCxhrkvTO_taqxrCTG_L2ImDmQjMml6E3GXjYA9EFK0NfWquUI2mdSMAqohX-ndffN0fa5cChdcMJEm3XS9tt6-_zzhoOojK-q9MHF7huZg4O1587xhSofxs-KS7BeYxEHKn_10tAkjEIo9QtYUE7zD7JXwGUsvfMMjOqEVW6KuY3ZOmIq_ncKlB4jvbdrduxy1pbky_kvzHWlE9El_N5qveQXyuvNZVMSIEpw8_y5iSxPxKfrVwGY7hBaF40Oph-d2PO7AzKvxEVMamzLvMGBMaRAP_WttBPAUSqTU5uMXwMafryhGdIcQVsDPcGNgMX6E1jzLA", "expires_in": 3600, "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiI1YzlmNzVjN2NjZjg3YjA1YTkyMWU5YjAiLCJub25jZSI6IjIyMTIxIiwiYXRfaGFzaCI6Ik5kbW9iZVBZOEFFaWQ2T216MzIyOXciLCJzaWQiOiI1ODM2NzllNC1lYWM5LTRjNDEtOGQxMS1jZWFkMmE5OWQzZWIiLCJhdWQiOiI1Y2E3NjVlMzkzMTk0ZDU4OTFkYjE5MjciLCJleHAiOjE1NTQ1NDE0NjksImlhdCI6MTU1NDUzNzg2OSwiaXNzIjoiaHR0cHM6Ly9hdXRoaW5nLmNuIn0.IQi5FRHO756e_eAmdAs3OnFMU7QuP-XtrbwCZC1gJntevYJTltEg1CLkG7eVhdi_g5MJV1c0pNZ_xHmwS0R-E4lAXcc1QveYKptnMroKpBWs5mXwoOiqbrjKEmLMaPgRzCOdLiSdoZuQNw_z-gVhFiMNxI055TyFJdXTNtExt1O3KmwqanPNUi6XyW43bUl29v_kAvKgiOB28f3I0fB4EsiZjxp1uxHQBaDeBMSPaRVWQJcIjAJ9JLgkaDt1j7HZ2a1daWZ4HPzifDuDfi6_Ob1ZL40tWEC7xdxHlCEWJ4pUIsDjvScdQsez9aV_xMwumw3X4tgUIxFOCNVEvr73Fg", "refresh_token": "WPsGJbvpBjqXz6IJIr1UHKyrdVF", "scope": "openid profile offline_access phone email", "token_type": "Bearer" } 验证 access_token 和 id_token 的合法性 OIDC 默认使用 OIDC 应用的 secret 对 token 进行验证(也就是在创建应用时默认选择 HS256 算法)。 如果你使用 javascript 那么可以使用 jsonwebtoken 进行验证: const jwt = require('jsonwebtoken'); let decoded = jwt.verify(token, <appSecret>); 如果是其他语言,那么你在服务端需要用 app_secret 作为 HS256 签名参数来计算签名和 JWT 中的签名进行对比,伪代码如下: HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), "1133fd20c14e4cc29b6ecb71fb8eb952"// app_secret ) 如果是 RS256 等非对称加密算法,需要使用公钥验证签名。Authing 将使用私钥进行签名,请使用 Authing 的公钥来验证签名: -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxRijj2seoesv5K0Z+ymR K7DSDPxdsM2sGQD2ZVhLjLsxZWJtXUXh7ERdUU6OT3BqYZZf7CLIhN6yyNtTOgfg pLG9HVJd7ZSKzuy2dS7mo8jD8YRtptAJmNFqw6z8tQp5MNG1ZHqp9isKqJmx/CFY kRdXBmjjj8PMVSP757pkC3jCq7fsi0drSSg4lIxrSsGzL0++Ra9Du71Qe/ODQKU0 brxaI1OKILtfcVPTHTaheV+0dw4eYkSDtyaLBG3jqsQbdncNg8PCEWchNzdO6aaj Uq4wbOzy/Ctp399mz0SGKfuC5S8gqAFABFT3DH3UD21ZztQZwFEV2AlvF+bcGEst cwIDAQAB -----END PUBLIC KEY----- 使用 access_token 换取用户信息 开发者在自己的服务中可以使用 access_token 换取用户信息。根据 scope 的不同,这里的返回信息也会有所不同,字段符合 OIDC 规范,字段解释请参考用户信息字段含义。 请求链接: GET https://users.authing.cn/oauth/oidc/user/userinfo?access_token=<access_token> 返回示例: { "sub": "<用户在 Authing 的唯一标识>", "nickname": "Authing", "name": "张三", "locale": "en-US" } 更多字段解释请参考用户信息字段含义。 接下来你可能还需要 了解 OIDC 协议: 理解OIDC流程 控制台是你管理所有 Authing 资源的地方,了解 Authing 控制台各模块包含的内容和你可以在控制台中做的事情: 控制台概览 了解 Authing 提供的多种部署模型,以帮助你选择该以怎样的形式部署 Authing: 部署模型 什么是 Authing? Authing 提供专业的身份认证和授权服务。 我们为开发者和企业提供用以保证应用程序安全所需的认证模块,这让开发人员无需成为安全专家。 你可以将任意平台的应用接入到 Authing(无论是新开发的应用还是老应用都可以),同时你还可以自定义应用程序的登录方式(如:邮箱/密码、短信/验证码、扫码登录等)。 你可以根据你使用的技术,来选择我们的 SDK 或调用相关 API 来接入你的应用。当用户发起授权请求时,Authing 会帮助你认证他们的身份和返回必要的用户信息到你的应用中。 官网:http://authing.cn 小登录:https://wxapp.authing.cn/#/ 仓库:欢迎star,欢迎pr https://gitee.com/Authi_ng https://github.com/authing Demo: https://sample.authing.cn https://github.com/Authing/qrcode-sample 文档:https://docs.authing.cn/authing/

优秀的个人博客,低调大师

3分钟,了解阿里云热门产品 ZooKeeper

本文来自畅销书《从 Paxos 到 Zookeeper》作者倪超,讲述了其对阿里云最新发布的微服务引擎 MSE 产品的使用初体验。 (图片来自《从 Paxos 到 ZooKeeper 》一书的封面) 屏幕前的读者朋友们 如果 正在为运维 ZooKeeper 这份至关重要,但繁琐而枯燥 甚至心里没底的活 而烦恼 如果 正在为自己的应用 找寻一个高可用,且免运维的 ZooKeeper 那么,它来了 阿里云全托管的 ZooKeeper 集群产品 微服务引擎 MSE 读者可以在任何搜索引擎搜索“微服务引擎 MSE”,即可直达产品官网。 阿里巴巴和 ZooKeeper 的结缘 从微服务引擎 MSE 的官方网站上,了解到,自 2010 年左右第一次引入以来,Apache ZooKeeper 目前在阿里巴巴集团内部已经有了将近 10 年的发展,使用的场景非常广泛,基于 ZooK

优秀的个人博客,低调大师

Eclipse教程1 - 3分钟理清Maven依赖

作者: 韩勇 日期: 2018-12-02 前言 大学学习 Java 时开始接触 Eclipse,喜欢其强大和方便,并立志成为一名 Java 开发。然而近几年 Eclipse 的流行度开始下滑,一方面有 Eclipse 自身的不足(安装插件需要科学上网,新版卡顿、报错),一方面我在想是不是 Eclipse 更适合我这样熟练使用 Eclipse 的用户,而不是普通 Java 开发。我觉得我应该写一些教程,帮助大家了解和使用 Eclipse,作为对 Eclipse 社区的回馈。 安装 Eclipse 首先需要安装 JDK,Linux(或 Cygwin)下可使用 sdkman 安装(需要科学上网)。 sdk install java 8.0.191-oracle 下载解压 Eclipse Java 开发软件包,可从国内镜像加速下载,如

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册