feat: github oauth login view

pull/100/head
moonrailgun 2 years ago
parent ed1d7cc1d6
commit e81e7ad64f

@ -314,3 +314,11 @@ export const [pluginGroupConfigItems, regPluginGroupConfigItem] = buildRegList<{
loading: boolean;
}) => ReactElement;
}>();
/**
*
*/
export const [pluginLoginAction, regLoginAction] = buildRegList<{
name: string;
component: React.ComponentType;
}>();

@ -4,12 +4,10 @@ import {
isValidStr,
loginWithEmail,
t,
useAppSelector,
useAsyncFn,
useGlobalConfigStore,
} from 'tailchat-shared';
import React, { useEffect, useState } from 'react';
import { Spinner } from '../../components/Spinner';
import { string } from 'yup';
import { useLocation, useNavigate } from 'react-router';
import { setUserJWT } from '../../utils/jwt-helper';
@ -23,6 +21,7 @@ import { LanguageSelect } from '@/components/LanguageSelect';
import { EntryInput } from './components/Input';
import { SecondaryBtn } from './components/SecondaryBtn';
import { PrimaryBtn } from './components/PrimaryBtn';
import { pluginLoginAction } from '@/plugin/common';
/**
* TODO:
@ -156,6 +155,12 @@ export const LoginView: React.FC = React.memo(() => {
<Icon icon="mdi:arrow-right" className="ml-1 inline" />
</SecondaryBtn>
)}
{pluginLoginAction.map((item) => {
const { name, component: Component } = item;
return <Component key={name} />;
})}
</div>
<div className="absolute bottom-4 left-0 space-x-2">

@ -1,6 +1,7 @@
import { Spinner } from '@/components/Spinner';
import clsx from 'clsx';
import React, { ButtonHTMLAttributes } from 'react';
import _omit from 'lodash/omit';
export const PrimaryBtn: React.FC<
ButtonHTMLAttributes<HTMLButtonElement> & {
@ -10,7 +11,7 @@ export const PrimaryBtn: React.FC<
return (
<button
disabled={props.loading}
{...props}
{..._omit(props, ['loading'])}
className={clsx(
'w-full py-2 px-4 mb-2 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50',
props.className

@ -26,6 +26,7 @@ class FimService extends TcService {
return availableStrategies.map((s) => ({
name: s.name,
type: s.type,
icon: s.icon,
}));
});
@ -71,7 +72,10 @@ class FimService extends TcService {
userId: fimRecord.userId,
});
return { type: 'token', token };
return generatePostMessageHtml({
type: 'token',
token: token,
});
}
// 不存在记录,查找是否已经注册过,如果已经注册过需要绑定,如果没有注册过则创建账号并绑定用户关系
@ -80,9 +84,7 @@ class FimService extends TcService {
});
if (!!userInfo) {
// 用户已存在,需要登录后才能确定绑定关系
return {
type: 'existed',
};
return generatePostMessageHtml({ type: 'existed' });
}
const newUserInfo: UserStructWithToken = await ctx.call(
@ -100,14 +102,21 @@ class FimService extends TcService {
userId: String(newUserInfo._id),
});
return {
return generatePostMessageHtml({
type: 'token',
isNew: true,
token: newUserInfo.token,
};
});
},
};
}
}
function generatePostMessageHtml(obj: Record<string, any>) {
return {
__raw: true,
html: `<script>window.postMessage(${JSON.stringify(obj)})</script>`,
};
}
export default FimService;

@ -15,12 +15,13 @@ const redirect_uri = `${config.apiUrl}/api/plugin:com.msgbyte.fim/github/redirec
export const GithubStrategy: StrategyType = {
name: 'github',
type: 'oauth',
icon: '/images/avatar/github-dark.svg',
checkAvailable: () => !!clientInfo.id && !!clientInfo.secret,
getUrl: () => {
return `${authorize_uri}?client_id=${clientInfo.id}&redirect_uri=${redirect_uri}`;
},
getUserInfo: async (code) => {
console.log('authorization code:', code);
console.log('[github oauth] authorization code:', code);
const tokenResponse = await got
.post(access_token_uri, {
@ -36,7 +37,7 @@ export const GithubStrategy: StrategyType = {
.json<{ access_token: string }>();
const accessToken = tokenResponse.access_token;
console.log(`access token: ${accessToken}`);
console.log(`[github oauth] access token: ${accessToken}`);
const result = await got
.get(userinfo_uri, {
@ -47,6 +48,8 @@ export const GithubStrategy: StrategyType = {
})
.json<{ id: number; name: string; email: string; avatar_url: string }>();
console.log(`[github oauth] user info:`, result);
return {
id: String(result.id),
nickname: result.name,

@ -1,6 +1,7 @@
export interface StrategyType {
name: string;
type: 'oauth';
icon: string;
checkAvailable: () => boolean;
getUrl: () => string;
getUserInfo: (code: string) => Promise<{

@ -0,0 +1,54 @@
import React from 'react';
import { useAsync } from '@capital/common';
import { Divider, Image, Tooltip } from '@capital/component';
import { request } from './request';
export const FimAction: React.FC = React.memo(() => {
const { loading, value: strategies } = useAsync(async () => {
const { data: strategies } = await request.get('availableStrategies');
return strategies;
}, []);
if (loading) {
return null;
}
if (Array.isArray(strategies) && strategies.length > 0) {
return (
<div>
<Divider />
<div style={{ display: 'flex', justifyContent: 'center' }}>
{strategies.map((s) => (
<Tooltip key={s.name} title={s.name}>
<Image
style={{
width: 40,
height: 40,
cursor: 'pointer',
borderRadius: 20,
}}
src={s.icon}
onClick={async () => {
if (s.type === 'oauth') {
const { data: url } = await request.get(
`${s.name}.loginUrl`
);
const win = window.open(url, 'square', 'frame=true');
win.addEventListener('message', (...args) => {
console.log(...args);
});
}
}}
/>
</Tooltip>
))}
</div>
</div>
);
}
return null;
});
FimAction.displayName = 'FimAction';

@ -1 +1,9 @@
import { regLoginAction } from '@capital/common';
import { FimAction } from './FimAction';
console.log('Plugin Federated Identity Management is loaded');
regLoginAction({
name: 'fim',
component: FimAction,
});

@ -0,0 +1,3 @@
import { createPluginRequest } from '@capital/common';
export const request = createPluginRequest('com.msgbyte.fim');
Loading…
Cancel
Save