王熙凤穿越到 2022 年,一定会采购的单点登录服务
随着企业业务的发展,OA 系统、财税系统、CRM 系统等各类系统只增不减,权限管理也日渐力不从心。很多企业都在寻找这样一种服务——员工只需登录个人 OA 系统的账号密码,就可以访问飞书、销售易、客户系统等应用程序。
单点登录(Single Sign On,SSO)就可以解决这一痛点。它是指一种思想或服务,用户只需使用一次登录凭据,其他所有被授权的应用都自动处于登录态。
还记得小时候看的《红楼梦》吗?
黛玉初入贾府时,轿夫抬着她进了西边角门没走两步,转弯处就换了一帮衣帽周全的小厮来抬轿,等过了垂花门,又得由婆子们引入正房大院。
如果王熙凤为贾府购买了单点登录服务,那么黛玉进贾府就不必这么处处小心、步步留意了。只要她进了大门,其他的小门就会自动打开,畅行无阻。
如果企业自研身份模块,时间和人力成本的投入都很大。而使用 Authing 单点登录,用几行代码就可以集成登录系统,支持用户统一登录。
这是因为,Authing 提供完善易用的文档,并且支持主流编程语言的 SDK 。开发者可以通过直接调用 SDK 接口与 Authing 完成集成,为多个业务软件在 web 内实现跨主域的单点登录效果。
创建自建应用
也可以使用现有应用。
应用名称:你的应用名称;
认证地址:选择一个二级域名,必须为合法的域名格式,例如
my-spa-app
;
配置单点登录
修改配置
认证配置:配置
登录回调 URL
授权配置:
授权模式
开启authorization_code
、refresh_token
授权配置:
返回类型
开启code
点击保存进行保存配置
安装
<script>
const sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '认证域名',
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调地址'
});
</script>
初始化
应用 ID
、认证域名
、回调地址
等参数,如下示例:const sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '认证域名',
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调地址'
});
登录
在当前窗口转到 Authing 托管的登录页;
弹出一个窗口,在弹出的窗口中加载 Authing 托管的登录页;
静默登录。
React
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
function App() {
const sdk = useMemo(() => {
return new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '单点登录的“应用面板地址”',
// 应用 ID
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调 URL',
});
}, []);
const [loginState, setLoginState] = useState<LoginState | null>();
/**
* 以跳转方式打开 Authing 托管的登录页
*/
const login = () => {
sdk.loginWithRedirect();
};
/**
* 获取用户的登录状态
*/
const getLoginState = useCallback(async () => {
const state = await sdk.getLoginState();
setLoginState(state);
}, [sdk]);
useEffect(() => {
// 判断当前 URL 是否为 Authing 登录回调 URL
if (sdk.isRedirectCallback()) {
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
sdk.handleRedirectCallback().then((res) => setLoginState(res));
} else {
getLoginState();
}
}, [getLoginState, sdk]);
return (
<div className="App">
<p>
<button onClick={login}>loginWithRedirect</button>
</p>
<p>
<code>{JSON.stringify(loginState)}</code>
</p>
</div>
);
}
export default App;
Vue2
<template>
<div id="app">
<p>
<button @click="login">loginWithRedirect</button>
</p>
<p v-if="loginState">
<textarea
cols="100"
rows="20"
readOnly
:value="JSON.stringify(loginState, null, 2)"
></textarea>
</p>
</div>
</template>
<script>
import { Authing } from "@authing/browser";
export default {
name: "App",
data() {
return {
sdk: null,
loginState: null,
};
},
created() {
this.sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: "单点登录的'应用面板地址'",
// 应用 ID
appId: "应用 ID",
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: "登录回调 URL",
});
},
mounted() {
// 校验当前 url 是否是登录回调地址
if (this.sdk.isRedirectCallback()) {
console.log("redirect");
this.sdk.handleRedirectCallback().then((res) => {
this.loginState = res;
window.location.replace("/");
});
} else {
this.getLoginState();
}
},
methods: {
/**
* 以跳转方式打开 Authing 托管的登录页
*/
login() {
this.sdk.loginWithRedirect();
},
/**
* 获取用户的登录状态
*/
async getLoginState() {
const state = await this.sdk.getLoginState();
this.loginState = state;
},
},
};
</script>
Vue3
<template>
<div>
<p>
<button @click="login">loginWithRedirect</button>
</p>
<p v-if="loginState">
<textarea
cols="100"
rows="20"
readOnly
:value="JSON.stringify(loginState, null, 2)"
></textarea>
</p>
</div>
</template>
<script>
import { defineComponent, onMounted, reactive, toRefs } from "vue";
import { Authing } from "@authing/browser";
export default defineComponent({
name: "App",
setup() {
const sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: "单点登录的'应用面板地址'",
// 应用 ID
appId: "应用 ID",
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: "登录回调 URL",
});
const state = reactive({
loginState: null,
});
/**
* 获取用户的登录状态
*/
const getLoginState = async () => {
const res = await sdk.getLoginState();
state.loginState = res;
};
/**
* 以跳转方式打开 Authing 托管的登录页
*/
const login = () => {
sdk.loginWithRedirect();
};
onMounted(() => {
// 校验当前 url 是否是登录回调地址
if (sdk.isRedirectCallback()) {
console.log("redirect");
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
sdk.handleRedirectCallback().then((res) => {
state.loginState = res;
window.location.replace("/");
});
} else {
getLoginState();
}
});
return {
...toRefs(state),
login,
};
},
});
</script>
Angular
// <!-- src/app/app.component.ts -->
import { Component } from '@angular/core';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
loginState: LoginState | null = null;
private sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '单点登录的"应用面板地址"',
// 应用 ID
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调 URL',
});
ngOnInit() {
// 校验当前 url 是否是登录回调地址
if (this.sdk.isRedirectCallback()) {
console.log('redirect');
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
this.sdk.handleRedirectCallback().then((res) => {
this.loginState = res;
window.location.replace('/');
});
} else {
this.getLoginState();
}
}
/**
* 以跳转方式打开 Authing 托管的登录页
*/
login() {
this.sdk.loginWithRedirect();
}
/**
* 获取用户的登录状态
*/
async getLoginState() {
const state = await this.sdk.getLoginState();
this.loginState = state;
}
}
左右滑动查看更多
React
const login = () => {
const params: {
// 回调地址,默认为初始化参数中的 redirectUri
redirectUri?: string;
// 发起登录的 URL,若设置了 redirectToOriginalUri 会在登录结束后重定向回到此页面,默认为当前 URL
originalUri?: string;
// 即使在用户已登录时也提示用户再次登录
forced?: boolean;
// 自定义的中间状态,会被传递到回调端点
customState?: any;
} = {
redirectUri: '回调地址',
originalUri: '发起登录的 URL',
forced: false,
customState: {},
}
sdk.loginWithRedirect(params);
};
Vue2
export default {
...
methods: {
/**
* 以跳转方式打开 Authing 托管的登录页
*/
login() {
const params = {
// 回调地址,默认为初始化参数中的 redirectUri
redirectUri: "回调地址",
// 发起登录的 URL,若设置了 redirectToOriginalUri 会在登录结束后重定向回到此页面,默认为当前 URL
originalUri: "发起登录的 URL",
// 即使在用户已登录时也提示用户再次登录
forced: false,
// 自定义的中间状态,会被传递到回调端点
customState: {},
};
this.sdk.loginWithRedirect(params);
},
...
},
...
}
Vue3
export default {
...
setup() {
/**
* 以跳转方式打开 Authing 托管的登录页
*/
const login = () => {
const params = {
// 回调地址,默认为初始化参数中的 redirectUri
redirectUri: "回调地址",
// 发起登录的 URL,若设置了 redirectToOriginalUri 会在登录结束后重定向回到此页面,默认为当前 URL
originalUri: "发起登录的 URL",
// 即使在用户已登录时也提示用户再次登录
forced: false,
// 自定义的中间状态,会被传递到回调端点
customState: {},
};
sdk.loginWithRedirect(params);
}
return {
login
}
}
...
}
Angular
export class AppComponent {
...
/**
* 以跳转方式打开 Authing 托管的登录页
*/
login() {
const params: {
// 回调地址,默认为初始化参数中的 redirectUri
redirectUri?: string;
// 发起登录的 URL,若设置了 redirectToOriginalUri 会在登录结束后重定向回到此页面,默认为当前 URL
originalUri?: string;
// 即使在用户已登录时也提示用户再次登录
forced?: boolean;
// 自定义的中间状态,会被传递到回调端点
customState?: any;
} = {
redirectUri: '回调地址',
originalUri: '发起登录的 URL',
forced: false,
customState: {},
}
this.sdk.loginWithRedirect(params);
}
...
}
左右滑动查看更多
React
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
function App() {
const sdk = useMemo(() => {
return new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '单点登录的“应用面板地址”',
// 应用 ID
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调 URL',
});
}, []);
const [loginState, setLoginState] = useState<LoginState | null>();
/**
* 以弹窗方式打开 Authing 托管的登录页
*/
const login = async () => {
const res = await sdk.loginWithPopup();
setLoginState(res);
};
/**
* 获取用户的登录状态
*/
const getLoginState = useCallback(async () => {
const state = await sdk.getLoginState();
setLoginState(state);
}, [sdk]);
useEffect(() => {
getLoginState();
}, [getLoginState]);
return (
<div className="App">
<p>
<button onClick={login}>login</button>
</p>
<p>
<code>{JSON.stringify(loginState)}</code>
</p>
</div>
);
}
export default App;
Vue2
<template>
<div id="app">
<p>
<button @click="login">loginWithPopup</button>
</p>
<p v-if="loginState">
<textarea
cols="100"
rows="20"
readOnly
:value="JSON.stringify(loginState, null, 2)"
></textarea>
</p>
</div>
</template>
<script>
import { Authing } from "@authing/browser";
export default {
name: "App",
data() {
return {
sdk: null,
loginState: null,
};
},
created() {
this.sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: "单点登录的'应用面板地址'",
// 应用 ID
appId: "应用 ID",
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: "登录回调 URL",
});
},
mounted() {
this.getLoginState();
},
methods: {
/**
* 以弹窗方式打开 Authing 托管的登录页
*/
async login() {
const res = await this.sdk.loginWithPopup();
this.loginState = res;
},
/**
* 获取用户的登录状态
*/
async getLoginState() {
const state = await this.sdk.getLoginState();
this.loginState = state;
},
},
};
</script>
Vue3
<template>
<div>
<p>
<button @click="login">loginWithPopup</button>
</p>
<p v-if="loginState">
<textarea
cols="100"
rows="20"
readOnly
:value="JSON.stringify(loginState, null, 2)"
></textarea>
</p>
</div>
</template>
<script>
import { defineComponent, onMounted, reactive, toRefs } from "vue";
import { Authing } from "@authing/browser";
export default defineComponent({
name: "App",
setup() {
const sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: "单点登录的'应用面板地址'",
// 应用 ID
appId: "应用 ID",
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: "登录回调 URL",
});
const state = reactive({
loginState: null,
});
/**
* 获取用户的登录状态
*/
const getLoginState = async () => {
const res = await sdk.getLoginState();
state.loginState = res;
};
/**
* 以弹窗方式打开 Authing 托管的登录页
*/
const login = async () => {
const res = await sdk.loginWithPopup();
state.loginState = res;
};
onMounted(getLoginState);
return {
...toRefs(state),
login,
};
},
});
</script>
Angular
<!-- src/app/app.component.html -->
<div>
<p>
<button (click)="login()">loginWithPopup</button>
</p>
<p *ngIf="loginState">
<textarea cols="100" rows="20" readOnly>{{ loginState | json }}</textarea>
</p>
</div>
// <!-- src/app/app.component.ts -->
import { Component } from '@angular/core';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
loginState: LoginState | null = null;
private sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '单点登录的"应用面板地址"',
// 应用 ID
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调 URL',
});
ngOnInit() {
this.getLoginState();
}
/**
* 以弹窗方式打开 Authing 托管的登录页
*/
async login() {
const res = await this.sdk.loginWithPopup();
this.loginState = res;
}
/**
* 获取用户的登录状态
*/
async getLoginState() {
const state = await this.sdk.getLoginState();
this.loginState = state;
}
}
左右滑动查看更多
React
const login = async () => {
const params: {
// 回调地址,默认为初始化参数中的 redirectUri
redirectUri?: string;
// 即使在用户已登录时也提示用户再次登录
forced?: boolean;
} = {
redirectUri: '回调地址',
forced: false,
};
const res = await sdk.loginWithPopup(params);
setLoginState(res);
};
Vue2
export default {
...
data() {
return {
sdk: null,
loginState: null,
}
},
methods: {
/**
* 以弹窗方式打开 Authing 托管的登录页
*/
async login() {
const params = {
// 回调地址,默认为初始化参数中的 redirectUri
redirectUri: "回调地址",
// 即使在用户已登录时也提示用户再次登录
forced: false,
};
const res = await this.sdk.loginWithPopup(params);
this.loginState = res;
},
...
},
...
}
Vue3
export default {
...
setup() {
/**
* 以弹窗方式打开 Authing 托管的登录页
*/
const login = async () => {
const params = {
// 回调地址,默认为初始化参数中的 redirectUri
redirectUri: "回调地址",
// 即使在用户已登录时也提示用户再次登录
forced: false,
};
const res = await sdk.loginWithPopup(params);
state.loginState = res;
};
return {
login
}
}
...
}
Angular
export class AppComponent {
...
/**
* 以弹窗方式打开 Authing 托管的登录页
*/
async login() {
const params: {
// 回调地址,默认为初始化参数中的 redirectUri
redirectUri?: string;
// 即使在用户已登录时也提示用户再次登录
forced?: boolean;
} = {
redirectUri: '回调地址',
forced: false,
};
const res = await this.sdk.loginWithPopup(params);
this.loginState = res;
};
...
}
左右滑动查看更多
React
import React, { useEffect, useMemo, useState } from 'react';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
function App() {
const sdk = useMemo(() => {
return new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '单点登录的“应用面板地址”',
// 应用 ID
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调 URL',
});
}, []);
const [loginState, setLoginState] = useState<LoginState | null>();
useEffect(() => {
// 判断当前 URL 是否为 Authing 登录回调 URL
if (sdk.isRedirectCallback()) {
console.log('redirect');
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
sdk.handleRedirectCallback().then((res) => setLoginState(res));
} else {
console.log('normal');
// 获取用户的登录状态
sdk.getLoginState().then((res) => {
if (res) {
setLoginState(res);
} else {
// 如果用户没有登录,跳转认证中心
sdk.loginWithRedirect();
}
});
}
}, [sdk]);
return (
<div>
<p>
Access Token: <code>{loginState?.accessToken}</code>
</p>
<p>
User Info: <code>{JSON.stringify(loginState?.parsedIdToken)}</code>
</p>
<p>
Access Token Info:
<code>{JSON.stringify(loginState?.parsedAccessToken)}</code>
</p>
<p>
Expire At: <code>{loginState?.expireAt}</code>
</p>
</div>
);
}
export default App;
Vue2
<template>
<div id="app">
<p v-if="loginState">
<textarea
cols="100"
rows="20"
readOnly
:value="JSON.stringify(loginState, null, 2)"
></textarea>
</p>
</div>
</template>
<script>
import { Authing } from "@authing/browser";
export default {
name: "App",
data() {
return {
sdk: null,
loginState: null,
};
},
created() {
this.sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: "单点登录的'应用面板地址'",
// 应用 ID
appId: "应用 ID",
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: "登录回调 URL",
});
},
mounted() {
// 校验当前 url 是否是登录回调地址
if (this.sdk.isRedirectCallback()) {
console.log("redirect");
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
this.sdk.handleRedirectCallback().then((res) => {
this.loginState = res;
window.location.replace("/");
});
} else {
console.log("normal");
this.sdk.getLoginState().then((res) => {
if (res) {
this.loginState = res;
} else {
// 静默登录。取不到用户信息直接跳转到授权中心
this.sdk.loginWithRedirect();
}
});
}
},
};
</script>
Vue3
<template>
<p v-if="loginState">
<textarea
cols="100"
rows="20"
readOnly
:value="JSON.stringify(loginState, null, 2)"
></textarea>
</p>
</template>
<script>
import { defineComponent, onMounted, reactive, toRefs } from "vue";
import { Authing } from "@authing/browser";
export default defineComponent({
name: "App",
setup() {
const sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: "单点登录的'应用面板地址'",
// 应用 ID
appId: "应用 ID",
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: "登录回调 URL",
});
const state = reactive({
loginState: null,
});
/**
* 获取用户的登录状态
*/
const getLoginState = async () => {
const res = await sdk.getLoginState();
state.loginState = res;
if (!res) {
sdk.loginWithRedirect();
}
};
onMounted(() => {
// 校验当前 url 是否是登录回调地址
if (sdk.isRedirectCallback()) {
console.log("redirect");
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
sdk.handleRedirectCallback().then((res) => {
state.loginState = res;
window.location.replace("/");
});
} else {
console.log("normal");
// 静默登录,直接获取到用户信息
getLoginState();
}
});
return {
...toRefs(state),
};
},
});
</script>
Angular
<div>
<p *ngIf="loginState">
<textarea cols="100" rows="20" readOnly>{{ loginState | json }}</textarea>
</p>
</div>
import { Component } from '@angular/core';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
loginState: LoginState | null = null;
private sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '单点登录的"应用面板地址"',
// 应用 ID
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调地址',
});
ngOnInit() {
// 校验当前 url 是否是登录回调地址
if (this.sdk.isRedirectCallback()) {
console.log('redirect');
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
this.sdk.handleRedirectCallback().then((res) => {
this.loginState = res;
window.location.replace('/');
});
} else {
console.log('normal');
this.getLoginState();
}
}
/**
* 获取用户的登录状态
*/
async getLoginState() {
const res = await this.sdk.getLoginState();
if (res) {
this.loginState = res;
} else {
// 静默登录。取不到用户信息直接跳转到授权中心
this.sdk.loginWithRedirect();
}
}
}
左右滑动查看更多
高级使用
const sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '认证域名',
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调地址',
// 应用侧向 Authing 请求的权限,以空格分隔,默认为 'openid profile'
scope: 'openid email phone profile',
// 回调时在何处携带身份凭据,默认为 fragment
// fragment: 在 URL hash 中携带
// query: 在查询参数中携带
responseMode: 'fragment',
// 是否使用 OIDC implicit 模式替代默认的 PKCE 模式
// 由于 implicit 模式安全性较低,不推荐使用,只用于兼容不支持 crypto 的浏览器
useImplicitMode: false,
// implicit 模式返回的凭据种类,默认为 'token id_token'
// token: 返回 Access Token
// id_token: 返回 ID Token
implicitResponseType: 'token id_token',
// 是否在每次获取登录态时请求 Authing 检查 Access Token 有效性,可用于单点登出场景,默认为 false
// 如果设为 true,需要在控制台中将『应用配置』-『其他配置』-『检验 token 身份验证方式』设为 none
introspectAccessToken: false,
// 弹出窗口的宽度
popupWidth: 500,
// 弹出窗口的高度
popupHeight: 600,
});
检查登录态并获取 Token
Access Token
、ID Token
,可以调用 getLoginState
方法,如果用户没有在 Authing 登录,该方法会抛出错误:React
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
function App() {
const sdk = useMemo(() => {
return new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '单点登录的“应用面板地址”',
// 应用 ID
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调 URL',
});
}, []);
const [loginState, setLoginState] = useState<LoginState | null>();
/**
* 以跳转方式打开 Authing 托管的登录页
*/
const login = () => {
sdk.loginWithRedirect();
};
/**
* 获取用户的登录状态
*/
const getLoginState = useCallback(async () => {
const state = await sdk.getLoginState();
setLoginState(state);
}, [sdk]);
useEffect(() => {
// 判断当前 URL 是否为 Authing 登录回调 URL
if (sdk.isRedirectCallback()) {
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
sdk.handleRedirectCallback().then((res) => setLoginState(res));
} else {
getLoginState();
}
}, [getLoginState, sdk]);
return (
<div className="App">
<p>
<button onClick={login}>login</button>
</p>
<p>
<code>{JSON.stringify(loginState)}</code>
</p>
</div>
);
}
export default App;
Vue2
<template>
<div id="app">
<p>
<button @click="login">loginWithRedirect</button>
</p>
<p v-if="loginState">
<textarea
cols="100"
rows="20"
readOnly
:value="JSON.stringify(loginState, null, 2)"
></textarea>
</p>
</div>
</template>
<script>
import { Authing } from "@authing/browser";
export default {
name: "App",
data() {
return {
sdk: null,
loginState: null,
};
},
created() {
this.sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: "单点登录的'应用面板地址'",
// 应用 ID
appId: "应用 ID",
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: "登录回调 URL",
});
},
mounted() {
// 校验当前 url 是否是登录回调地址
if (this.sdk.isRedirectCallback()) {
console.log("redirect");
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
this.sdk.handleRedirectCallback().then((res) => {
this.loginState = res;
window.location.replace("/");
});
} else {
console.log("normal");
this.getLoginState();
}
},
methods: {
/**
* 获取用户的登录状态
*/
async getLoginState() {
const state = await this.sdk.getLoginState();
this.loginState = state;
},
/**
* 以跳转方式打开 Authing 托管的登录页
*/
login() {
this.sdk.loginWithRedirect();
},
},
};
</script>
Vue3
<template>
<div>
<p>
<button @click="login">loginWithRedirect</button>
</p>
<p v-if="loginState">
<textarea
cols="100"
rows="20"
readOnly
:value="JSON.stringify(loginState, null, 2)"
></textarea>
</p>
</div>
</template>
<script>
import { defineComponent, onMounted, reactive, toRefs } from "vue";
import { Authing } from "@authing/browser";
export default defineComponent({
name: "App",
setup() {
const sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: "单点登录的'应用面板地址'",
// 应用 ID
appId: "应用 ID",
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: "登录回调 URL",
});
const state = reactive({
loginState: null,
});
/**
* 获取用户的登录状态
*/
const getLoginState = async () => {
const res = await sdk.getLoginState();
state.loginState = res;
if (!res) {
sdk.loginWithRedirect();
}
};
/**
* 以跳转方式打开 Authing 托管的登录页
*/
const login = () => {
sdk.loginWithRedirect();
};
onMounted(() => {
// 校验当前 url 是否是登录回调地址
if (sdk.isRedirectCallback()) {
console.log("redirect");
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
sdk.handleRedirectCallback().then((res) => {
state.loginState = res;
window.location.replace("/");
});
} else {
console.log("normal");
// 静默登录,直接获取到用户信息
getLoginState();
}
});
return {
...toRefs(state),
login,
};
},
});
</script>
Angular
<!-- src/app/app.component.html -->
<div>
<p>
<button (click)="login()">loginWithRedirect</button>
</p>
<p *ngIf="loginState">
<textarea cols="100" rows="20" readOnly>{{ loginState | json }}</textarea>
</p>
</div>
// <!-- src/app/app.component.ts -->
import { Component } from '@angular/core';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
loginState: LoginState | null = null;
private sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '单点登录的"应用面板地址"',
// 应用 ID
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调 URL',
});
ngOnInit() {
// 校验当前 url 是否是登录回调地址
if (this.sdk.isRedirectCallback()) {
console.log('redirect');
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
this.sdk.handleRedirectCallback().then((res) => {
this.loginState = res;
window.location.replace('/');
});
} else {
this.getLoginState();
}
}
/**
* 以跳转方式打开 Authing 托管的登录页
*/
login() {
this.sdk.loginWithRedirect();
}
/**
* 获取用户的登录状态
*/
async getLoginState() {
const state = await this.sdk.getLoginState();
this.loginState = state;
}
}
左右滑动查看更多
获取用户信息
你需要使用 Access Token 获取用户的个人信息:
用户初次登录成功时可以在回调函数中拿到用户的 Access Token,然后使用 Access Token 获取用户信息;
如果用户已经登录,你可以先获取用户的 Access Token ,然后使用 Access Token 获取用户信息。
React
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Authing } from '@authing/browser';
import type { LoginState, UserInfo } from '@authing/browser/dist/types/global';
function App() {
const sdk = useMemo(() => {
return new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '单点登录的“应用面板地址”',
// 应用 ID
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调 URL',
});
}, []);
const [loginState, setLoginState] = useState<LoginState | null>();
const [userInfo, setUserInfo] = useState<UserInfo | null>();
/**
* 以跳转方式打开 Authing 托管的登录页
*/
const login = () => {
sdk.loginWithRedirect();
};
/**
* 获取用户的登录状态
*/
const getLoginState = useCallback(async () => {
const state = await sdk.getLoginState();
setLoginState(state);
}, [sdk]);
/**
* 用 Access Token 获取用户身份信息
*/
const getUserInfo = async () => {
if (!loginState) {
alert("用户未登录");
return;
}
const userInfo = await sdk.getUserInfo({
accessToken: loginState?.accessToken,
});
setUserInfo(userInfo);
};
useEffect(() => {
// 判断当前 URL 是否为 Authing 登录回调 URL
if (sdk.isRedirectCallback()) {
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
sdk.handleRedirectCallback().then((res) => setLoginState(res));
} else {
getLoginState();
}
}, [getLoginState, sdk]);
return (
<div className="App">
<p>
<button onClick={login}>login</button>
<button onClick={getUserInfo}>getUserInfo</button>
</p>
<p>
loginState:
<code>{JSON.stringify(loginState)}</code>
</p>
<p>
userInfo:
<code>{JSON.stringify(userInfo)}</code>
</p>
</div>
);
}
export default App;
Vue2
<template>
<div id="app">
<p>
<button @click="login">loginWithRedirect</button>
<button @click="getUserInfo">getUserInfo</button>
</p>
<p v-if="loginState">
<textarea
cols="100"
rows="20"
readOnly
:value="JSON.stringify(loginState, null, 2)"
></textarea>
</p>
<p v-if="userInfo">
<textarea
cols="100"
rows="20"
readOnly
:value="JSON.stringify(userInfo, null, 2)"
></textarea>
</p>
</div>
</template>
<script>
import { Authing } from "@authing/browser";
export default {
name: "App",
data() {
return {
sdk: null,
loginState: null,
userInfo: null,
};
},
created() {
this.sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: "单点登录的'应用面板地址'",
// 应用 ID
appId: "应用 ID",
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: "登录回调 URL",
});
},
mounted() {
// 校验当前 url 是否是登录回调地址
if (this.sdk.isRedirectCallback()) {
console.log("redirect");
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
this.sdk.handleRedirectCallback().then((res) => {
this.loginState = res;
window.location.replace("/");
});
} else {
console.log("normal");
this.getLoginState();
}
},
methods: {
/**
* 用 Access Token 获取用户身份信息
*/
async getUserInfo() {
if (!this.loginState) {
alert("用户未登录");
return;
}
const userInfo = await this.sdk.getUserInfo({
accessToken: this.loginState.accessToken,
});
this.userInfo = userInfo;
},
/**
* 获取用户的登录状态
*/
async getLoginState() {
const state = await this.sdk.getLoginState();
this.loginState = state;
},
/**
* 以跳转方式打开 Authing 托管的登录页
*/
login() {
this.sdk.loginWithRedirect();
},
},
};
</script>
Vue3
<template>
<div>
<p>
<button @click="login">loginWithRedirect</button>
</p>
<p v-if="loginState">
<textarea
cols="100"
rows="20"
readOnly
:value="JSON.stringify(loginState, null, 2)"
></textarea>
</p>
<p>
<button @click="getUserInfo">getUserInfo</button>
</p>
<p v-if="userInfo">
<textarea
cols="100"
rows="15"
readOnly
:value="JSON.stringify(userInfo, null, 2)"
></textarea>
</p>
</div>
</template>
<script>
import { defineComponent, onMounted, reactive, toRefs } from "vue";
import { Authing } from "@authing/browser";
export default defineComponent({
name: "App",
setup() {
const sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: "单点登录的'应用面板地址'",
// 应用 ID
appId: "应用 ID",
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: "登录回调 URL",
});
const state = reactive({
loginState: null,
userInfo: null,
});
/**
* 获取用户的登录状态
*/
const getLoginState = async () => {
const res = await sdk.getLoginState();
state.loginState = res;
if (!res) {
sdk.loginWithRedirect();
}
};
/**
* 以跳转方式打开 Authing 托管的登录页
*/
const login = () => {
sdk.loginWithRedirect();
};
/**
* 用 Access Token 获取用户身份信息
*/
const getUserInfo = async () => {
if (!state.loginState) {
alert("用户未登录");
return;
}
const userInfo = await sdk.getUserInfo({
accessToken: state.loginState.accessToken,
});
state.userInfo = userInfo;
};
onMounted(() => {
// 校验当前 url 是否是登录回调地址
if (sdk.isRedirectCallback()) {
console.log("redirect");
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
sdk.handleRedirectCallback().then((res) => {
state.loginState = res;
window.location.replace("/");
});
} else {
console.log("normal");
// 静默登录,直接获取到用户信息
getLoginState();
}
});
return {
...toRefs(state),
login,
getUserInfo,
};
},
});
</script>
Angular
<!-- src/app/app.component.html -->
<div>
<p>
<button (click)="login()">loginWithRedirect</button>
<button (click)="getUserInfo()">getUserInfo</button>
</p>
<p *ngIf="loginState">
<textarea cols="100" rows="20" readOnly>{{ loginState | json }}</textarea>
</p>
<p *ngIf="userInfo">
<textarea cols="100" rows="20" readOnly>{{ userInfo | json }}</textarea>
</p>
</div>
// <!-- src/app/app.component.ts -->
import { Component } from '@angular/core';
import { Authing } from '@authing/browser';
import type { LoginState, UserInfo } from '@authing/browser/dist/types/global';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
loginState: LoginState | null = null;
userInfo: UserInfo | null = null;
private sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '单点登录的"应用面板地址"',
// 应用 ID
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调 URL',
});
ngOnInit() {
// 校验当前 url 是否是登录回调地址
if (this.sdk.isRedirectCallback()) {
console.log('redirect');
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
this.sdk.handleRedirectCallback().then((res) => {
this.loginState = res;
window.location.replace('/');
});
} else {
this.getLoginState();
}
}
/**
* 用 Access Token 获取用户身份信息
*/
async getUserInfo() {
if (!this.loginState) {
alert('用户未登录');
return;
}
const userInfo = await this.sdk.getUserInfo({
accessToken: this.loginState.accessToken,
});
this.userInfo = userInfo;
}
/**
* 以跳转方式打开 Authing 托管的登录页
*/
login() {
this.sdk.loginWithRedirect();
}
/**
* 获取用户的登录状态
*/
async getLoginState() {
const state = await this.sdk.getLoginState();
this.loginState = state;
}
}
左右滑动查看更多
退出登录
logoutWithRedirect
方法退出登录。React
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
function App() {
const sdk = useMemo(() => {
return new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '单点登录的“应用面板地址”',
// 应用 ID
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调 URL',
});
}, []);
const [loginState, setLoginState] = useState<LoginState | null>();
/**
* 以跳转方式打开 Authing 托管的登录页
*/
const login = () => {
sdk.loginWithRedirect();
};
/**
* 获取用户的登录状态
*/
const getLoginState = useCallback(async () => {
const state = await sdk.getLoginState();
setLoginState(state);
}, [sdk]);
/**
* 登出
*/
const logout = async () => {
await sdk.logoutWithRedirect();
};
useEffect(() => {
// 判断当前 URL 是否为 Authing 登录回调 URL
if (sdk.isRedirectCallback()) {
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
sdk.handleRedirectCallback().then((res) => setLoginState(res));
} else {
getLoginState();
}
}, [getLoginState, sdk]);
return (
<div className="App">
<p>
<button onClick={login}>login</button>
<button onClick={logout}>logout</button>
</p>
<p>
loginState:
<code>{JSON.stringify(loginState)}</code>
</p>
</div>
);
}
export default App;
Vue2
<template>
<div id="app">
<p>
<button @click="login">loginWithRedirect</button>
<button @click="logout">logout</button>
</p>
<p v-if="loginState">
<textarea
cols="100"
rows="20"
readOnly
:value="JSON.stringify(loginState, null, 2)"
></textarea>
</p>
</div>
</template>
<script>
import { Authing } from "@authing/browser";
export default {
name: "App",
data() {
return {
sdk: null,
loginState: null,
};
},
created() {
this.sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: "单点登录的'应用面板地址'",
// 应用 ID
appId: "应用 ID",
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: "登录回调 URL",
});
},
mounted() {
// 校验当前 url 是否是登录回调地址
if (this.sdk.isRedirectCallback()) {
console.log("redirect");
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
this.sdk.handleRedirectCallback().then((res) => {
this.loginState = res;
window.location.replace("/");
});
} else {
this.getLoginState();
}
},
methods: {
/**
* 以跳转方式打开 Authing 托管的登录页
*/
login() {
this.sdk.loginWithRedirect();
},
/**
* 登出
*/
logout() {
this.sdk.logoutWithRedirect();
},
/**
* 获取用户的登录状态
*/
async getLoginState() {
const state = await this.sdk.getLoginState();
this.loginState = state;
},
},
};
</script>
Vue3
<template>
<div>
<button @click="logout">logout</button>
</div>
</template>
<script>
import { defineComponent } from "vue";
import { Authing } from "@authing/browser";
export default defineComponent({
name: "App",
setup() {
const sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: "单点登录的'应用面板地址'",
// 应用 ID
appId: "应用 ID",
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: "登录回调 URL",
});
/**
* 登出
*/
const logout = () => {
sdk.logoutWithRedirect();
};
return {
logout,
};
},
});
</script>
Angular
<!-- src/app/app.component.html -->
<div>
<p>
<button (click)="login()">loginWithRedirect</button>
<button (click)="logout()">logout</button>
</p>
<p *ngIf="loginState">
<textarea cols="100" rows="20" readOnly>{{ loginState | json }}</textarea>
</p>
</div>
// <!-- src/app/app.component.ts -->
import { Component } from '@angular/core';
import { Authing } from '@authing/browser';
import type { LoginState } from '@authing/browser/dist/types/global';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
loginState: LoginState | null = null;
private sdk = new Authing({
// 很重要,请仔细填写!
// 如果应用开启 SSO,这儿就要写单点登录的“应用面板地址”;否则填写应用的“认证地址”。
domain: '单点登录的"应用面板地址"',
// 应用 ID
appId: '应用 ID',
// 登录回调地址,需要在控制台『应用配置 - 登录回调 URL』中指定
redirectUri: '登录回调 URL',
});
ngOnInit() {
// 校验当前 url 是否是登录回调地址
if (this.sdk.isRedirectCallback()) {
console.log('redirect');
/**
* 以跳转方式打开 Authing 托管的登录页,认证成功后需要配合 handleRedirectCallback 方法,
* 在回调端点处理 Authing 发送的授权码或 token,获取用户登录态
*/
this.sdk.handleRedirectCallback().then((res) => {
this.loginState = res;
window.location.replace('/');
});
} else {
this.getLoginState();
}
}
/**
* 以跳转方式打开 Authing 托管的登录页
*/
login() {
this.sdk.loginWithRedirect();
}
/**
* 登出
*/
logout() {
this.sdk.logoutWithRedirect();
}
/**
* 获取用户的登录状态
*/
async getLoginState() {
const state = await this.sdk.getLoginState();
this.loginState = state;
}
}
左右滑动查看更多
代码参考
https://github.com/Authing/authing-sso-demo/tree/feat-sso-v3-demo
https://github.com/Authing/authing-sso-demo/tree/feat-sso-v3-demo-vue2
https://github.com/Authing/authing-sso-demo/tree/feat-sso-v3-demo-vue3
https://github.com/Authing/authing-sso-demo/tree/feat-sso-v3-demo-angular
获取帮助
关于 Authing
Authing 身份云是国内唯一以开发者为中心的全场景 IDaaS 服务商,以身份及服务的云计算视角,基于多租户云原生架构,集成了所有主流身份认证协议,遵循不同国家和行业的合规性要求,在所有 SaaS 软件和数亿用户中建立高安全、高性能、高生产力的统一身份认证平台,支持所有企业和开发者便捷灵活接入,满足各类场景化需求。目前,Authing 身份云已帮助 20,000+ 家企业和开发者构建标准化的用户身份体系,感谢可口可乐、元气森林、招商银行、中国石油、三星集团等客户选择并实施 Authing 解决方案。
你所在的行业,都在重构身份管理体系。点击“阅读原文”,免费领取 Authing 产品体验券。↓↓↓