糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > Ory Kratos 用户认证

Ory Kratos 用户认证

时间:2023-04-16 11:44:33

相关推荐

Ory Kratos 用户认证

Ory Kratos 为用户认证与管理系统。本文将动手实现浏览器(React+AntD)的完整流程,实际了解下它的 API 。

代码: /ikuokuo/start-ory-kratos

了解 Kratos

获取代码

git clone -b v0.7.0-alpha.1 --depth 1 /ory/kratos.git

查看 API

go-swagger 查看:

cd kratosswagger serve -F=swagger ./spec/swagger.json

运行服务

docker-compose 运行:

cd kratosdocker-compose -f quickstart.yml -f quickstart-postgres.yml -f quickstart-standalone.yml up --build --force-recreate# If you have SELinux, run: -f quickstart-selinux.yml

运行了官方 Quickstart 例子,可以访问 http://127.0.0.1:4455/dashboard 体验。

查看 DB

pgAdmin 打开(DB 信息见quickstart-postgres.yml):

查看表:

查看配置

cd kratoscat contrib/quickstart/kratos/email-password/kratos.yml

设置环境变量可以覆盖。以_表示层级,如SELFSERVICE_FLOWS_SETTINGS_UI_URL=<value>覆盖selfservice.flows.settings.ui_url

Self-Service 流程

RegistrationLoginLogoutUser SettingsAccount RecoveryAddress VerificationUser-Facing Error2FA / MFA

浏览器流程

客户端流程

动手配置:Kratos 服务

Ory Kratos Public API (port 4433)Admin API (port 4434)Postgres DB (port 5432)Browser Return URL (port 3000) MailSlurper: a development SMTP server Server UI (port 4436)

配置文件

ory-kratos/config/kratos.yml: 配置文件ory-kratos/config/identity.schema.json: 认证 JSON 模式

启动文件

ory-kratos/start.yml: Docker Compose 文件

运行服务

cd ory-kratosdocker-compose -f start.yml up --build --force-recreate

如果想运行官方 Self-Service UI 例子,那么:

docker-compose -f start.yml -f start-ui-node.yml up --build --force-recreate

之后,访问 http://127.0.0.1:3000/ 体验。在Register new account/Reset password时,可访问虚拟 SMTP 服务 http://127.0.0.1:4436 接收邮件。

动手实现:浏览器流程

React + Ant Design

新建 React 应用

yarn create react-app my-web --template typescriptcd my-webyarn start

访问 http://localhost:3000/ ,可见 React 欢迎页。

引入 AntD

yarn add antd

修改src/App.tsx,引入 antd 组件:

import React, { Component } from 'react'import { Button } from 'antd';import logo from './logo.svg';import './App.css';class App extends Component {render() {return (<div className="App"><header className="App-header"><img src={logo} className="App-logo" alt="logo" /><Button type="primary">Button</Button></header></div>);}}export default App;

修改src/App.css,引入 antd 样式:

@import '~antd/dist/antd.css';

可见 antd 蓝色按钮组件。

引入 Sass

yarn add node-sass

后缀css改为scsstsx里的import也改下。

引入 Router

yarn add react-router-dom @types/react-router-dom

pages目录下实现如下页面 UI:

src/pages功能 路由├── dashboard.tsx 主页 /, /dashboard├── error.tsx 错误 /error├── login.tsx 登录 /auth/login├── recovery.tsx 恢复 /recovery├── registration.tsx 注册 /auth/registration├── settings.tsx 设置 /settings└── verification.tsx 验证 /verify

引入 SDK

yarn add @ory/kratos-client@0.7.0-alpha.1

注册

APIs:

GET/self-service/registration/browser: 初始化注册流程GET/self-service/registration/flows: 获取注册流程POST/self-service/registration: 提交注册流程

页面加载后的处理流程:

componentDidMount() {// 获取 flow id 参数const flowId = utils.parseUrlQuery("flow", this.props.location) as string;// 没有 flow id,初始化注册流程if (!flowId || !utils.isString(flowId)) {console.log("No flow ID found in URL, initializing registration flow.");utils.redirectToSelfService("/self-service/registration/browser");return;}// 根据 flow id,获取注册流程信息authPublicApi.getSelfServiceRegistrationFlow(flowId, undefined, {withCredentials: true,}).then((res: AxiosResponse<SelfServiceRegistrationFlow>) => {if (utils.assertResponse(res)) {utils.redirectToSelfService("/self-service/registration/browser");return;}this.setState({flowId: flowId, flow: res.data });}).catch(utils.redirectOnError);}

流程信息this.state.flow,如下:

{"id": "74c643a1-f302-45c9-a760-1ad7b1157e1c","type": "browser","expires_at": "-07-20T05:22:30.958717Z","issued_at": "-07-20T05:12:30.958717Z","request_url": "http://127.0.0.1:4433/self-service/registration/browser","ui": {"action": "http://127.0.0.1:4433/self-service/registration?flow=74c643a1-f302-45c9-a760-1ad7b1157e1c","method": "POST","nodes": [{"type": "input","group": "default","attributes": {"name": "csrf_token","type": "hidden","value": "QQyUDHa4KJ3M6mowHHN4pboN4iaUOZL+4gYVtKYRWzSdWjSNcW5dG/SNzocyqqqAtV48KzQVMIC6X+Pv3tNPNw==","required": true,"disabled": false},"messages": [],"meta": {}}, {"type": "input","group": "password","attributes": {"name": "traits.email","type": "email","disabled": false},"messages": [],"meta": {"label": {"id": 1070002,"text": "E-Mail","type": "info"}}}, {...}]}}

之后,依据流程信息创建表单:

<Card title="Register new account" bordered={false}>{/* 流程消息展示 */}{this.state.flow.ui.messages &&this.state.flow.ui.messages.map((m: UiText, index) => (<Alertkey={index}message={m.text}type={m.type as AlertProps["type"]}style={{ marginBottom: 16 }}showIcon/>))}{/* 流程表单创建 */}<Formname="register"ref={this.formRef}encType="application/x-www-form-urlencoded"action={this.state.flow.ui.action}method={this.state.flow.ui.method}onFinish={onFinish}>{this.state.flow.ui.nodes.map((node, index) => {return React.cloneElement(ui.toUiNodeAntd(node)!, {key: index,});})}</Form></Card>

其中表单onFinish里处理提交:

const onFinish = (values: any) => {// 因 AntD Form 不提交原 HTML form,所以自己创建 from 提交// - 不能直接 find form 提交,此时值已清空// - 创建 from 提交,与 AntD From 相互无影响ui.submitViaForm(this.state.flow!.ui, values);// 或者,用 `/self-service/registration/api` 提交// this.submitViaApi(values);};

登录

GET/self-service/login/browser: 初始化登录流程GET/self-service/login/flows: 获取登录流程POST/self-service/login: 提交登录流程

与注册流程一样。

登录后,可通过whoami获取授权信息:

GET/sessions/whoami: 获取授权信息

authPublicApi.toSession(undefined, undefined, {withCredentials: true,}).then((res: AxiosResponse<Session>) => {if (utils.assertResponse(res)) {utils.redirectToSelfService("/self-service/login/browser");return;}this.setState({session: res.data });}).catch((err: AxiosError) => utils.redirectOnError(err, "/auth/login"));

Dashboard页展示了授权信息:

验证

GET/self-service/verification/browser: 初始化验证流程GET/self-service/verification/flows: 获取验证流程POST/self-service/verification: 提交验证流程

与注册流程一样。

恢复

GET/self-service/recovery/browser: 初始化恢复流程GET/self-service/recovery/flows: 获取恢复流程POST/self-service/recovery: 提交恢复流程

与注册流程一样。

设置

GET/self-service/settings/browser: 初始化设置流程GET/self-service/settings/flows: 获取设置流程POST/self-service/settings: 完成设置流程

与注册流程一样。

但要注意的是,依据流程信息创建表单时,请区分group构建多个表单:

const nodesGroup: Record<string,{title?: string;nodes?: Array<UiNode>;}> = {default: {},profile: {title: "Profile" },password: {title: "Password" },oidc: {title: "Social Sign In" },};for (const [k, v] of Object.entries(nodesGroup)) {nodesGroup[k] = {title: v.title,nodes: ui.onlyNodes(this.state.flow!.ui.nodes, k),};}

<Card title="Settings" bordered={false}>{this.state.flow.ui.messages &&this.state.flow.ui.messages.map((m: UiText, index) => (<Alertkey={index}message={m.text}type={m.type as AlertProps["type"]}style={{ marginBottom: 16 }}showIcon/>))}{/* Split Form by group here. Otherwise, one AntD Form method conflicts. */}{Object.entries(nodesGroup).filter(([k, v]) => k !== "default" && v && v.nodes!.length > 0).map(([k, v], index) => (<Formkey={index}name={k}encType="application/x-www-form-urlencoded"action={this.state.flow!.ui.action}method={this.state.flow!.ui.method}onFinish={onFinish}><Form.Item><div>{v.title}</div></Form.Item>{v.nodes!.concat(nodesGroup["default"].nodes!).map((node, index) => {return React.cloneElement(ui.toUiNodeAntd(node)!, {key: index,});})}</Form>))}</Card>

登出

GET/self-service/logout/browser: 创建登出 URLPOST/self-service/logout: 完成登出流程

页面加载后创建登出 URL ,

authPublicApi.createSelfServiceLogoutFlowUrlForBrowsers(undefined, {withCredentials: true,}).then((res: AxiosResponse<SelfServiceLogoutUrl>) => {this.setState({logoutUrl: res.data.logout_url });}).catch((err) => {// console.log(err);});

之后,页面加上登出按钮:

{this.state.logoutUrl && (<Buttontype="link"shape="circle"href={this.state.logoutUrl}icon={<LogoutOutlined />}/>)}

参考

ORY Kratos ExpressJS Self-Service UI ReferenceKratos React Example

GoCoding 个人实践的经验分享,可关注公众号!

如果觉得《Ory Kratos 用户认证》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。