飞道科技

飞道科技文档总汇

app长效登录机制

长效登录有以下几种实现逻辑


A: 普通页面
B: 权限页面
C: 登录页面

一. 场景: A跳B

1.	商城类应用, session失效时间较长
	B页面初始化判断登录状态
	未登录, 显示引导登录按钮
	已登录, 渲染页面
2.	B页面初始化判断登录状态
	未登录, 跳C传递redirect参数
	登录成功, 跳回B
3.	A控制跳转的按钮判断登录状态
	未登录, 跳C传递redirect参数
	登录成功, 跳回B


二. B为财款相关的隐私级页面

session失效时间可能较短, 所以要增加判断环节
A页面跳转按钮判断, B显示事件判断, B前后台切换判断
未登录, 跳C, 未登录不可返回

在这里拿(一.2)作为例子, 演示长效登录的实现

完整例子见 demo-mobile的remember-me页面

项目地址: vic-git@192.168.40.199:feidao-edu/demo-mobile

一. 客户端登录逻辑及示例

登录页通过路由, 调用自定义登录服务。

需要传参用户名 usr , 密码 psw , 设备唯一标示 fdid

fdid 通过原子操作 @dfeidao/atom-mobile/device/get-uniqual-id 获取 , 需要添加依赖 react-native-device-info, 并执行 react-native link react-native-device-info

登录成功后, 需要通过url参数判断是否需要重定向

1.1 atom/config添加配置

export const remember_login = 'remember-login';

1.2 客户端登录逻辑

import get_uniqual_id from '@dfeidao/atom-mobile/device/get-uniqual-id';
import { IFeidaoAiMobile } from '@dfeidao/atom-mobile/interfaces';
import post from '@dfeidao/atom-mobile/msg/post';
import replace from '@dfeidao/atom-mobile/nav/replace';
import { remember_login } from '../atom/config';

export default async function a001(fd: IFeidaoAiMobile) {
	try {
		const fdid = get_uniqual_id();
		const res = await post(remember_login, JSON.stringify({
			usr: 'TS001',
			psw: '111111',
			fdid
		}));
		console.log(res);

		const params = fd.page.props.navigation.state.params;
		// 判断登录成功之后是否需要跳转
		const redirect = params.redirect;
		if (redirect) {
			replace(fd, redirect, params);
		} else {
			replace(fd, 'home', params);
		}
	} catch (err) {
		// todo  去处理登录出错的情况
		console.log(err);
	}
}

二. 登录服务逻辑及示例

通过参数获取用户名 usr , 密码 psw , 设备唯一标示 fdid

向项目经理确定ticket失效时间, 720代表30天

通过以上参数, 调用登录原子操作 @dfeidao/atom-nodejs/msg/login-and-remember-me

登录成功后返回用户信息, 把 fdid , ticket , sessionid 存至 cookie, 以供保持登录状态使用

2.1 feidao.json添加路由配置

{
	"url": "/remember-login",
	"method": "post",
	"service": "dataservice.nodejs",
	"data": {
		"modelid": "atom/remember-login-service"
	}
}

2.2 添加登录服务 src/atom/remember-login-service.ts

import logger from '@dfeidao/atom-nodejs/logger/log';
import login_and_remember_me from '@dfeidao/atom-nodejs/msg/login-and-remember-me';
import { IncomingHttpHeaders } from 'http';

interface Message {
	usr: string;
	psw: string;
	fdid: string;
}

interface IWebResult {
	data: unknown;
	cookie?: {
		[name: string]: string;
	} | null;
	content_type?: string;
	headers?: {
		[key: string]: string;
	};
	attachment?: string;
	redirect?: string;
	status_code?: number;
}

export default async function atom({ usr, psw, fdid }: Message, action_id: string, session_id: string, headers: IncomingHttpHeaders): Promise<IWebResult> {
	logger('Service begin path:atom/remember-login,action_id:' + action_id);
	const user_info = await login_and_remember_me(action_id, session_id, usr, psw, fdid, 720);	// !!! 这里的720为30天的保持状态时间,具体项目应找项目经理确定该值
	logger('Service end path:atom/remember-login,action_id:' + action_id);

	return {
		data: user_info,
		cookie: {
			fdid,
			ticket: user_info.remember_me_ticket,
			sessionid: user_info.sessionID
		}
	};
}

三. 页面初始化逻辑及示例

页面初始化, 需要使用ticket登录, 由于这个服务的使用频率很高, 所以封装为项目上的原子操作 ticket-login

ticket-login原子操作返回值为successfail, 如果返回值为 fail, 那么就需要跳转到登录页, 同时传递参数 { redirect: ‘当前页面路由地址’, …fd.page.props.navigation.state.params }

3.1 atom/config添加配置

export const ticket_login = 'ticket-login';

3.2 添加原子操作 src/atom/ticket-login.ts

import get_uniqual_id from '@dfeidao/atom-mobile/device/get-uniqual-id';
import post from '@dfeidao/atom-mobile/msg/post';
import { ticket_login } from './config';

export default async function aotm(): Promise<'success' | 'fail'> {
	const fdid = get_uniqual_id();
	return post(ticket_login, { fdid });
}

3.3 为页面初始化事件逻辑

import { IFeidaoAiMobile } from '@dfeidao/atom-mobile/interfaces';
import go from '@dfeidao/atom-mobile/nav/goto';
import ticket_login from '../atom/ticket-login';

// 初始化。保持登录状态
export default async function a001(fd: IFeidaoAiMobile, e: string) {
	const res = await ticket_login();
	if (res === 'fail') {
		// 跳转到登录页面
		go(fd, 'login', { redirect: 'xxx', ...fd.page.props.navigation.state.params });
	}
}

四. ticket登录服务逻辑及示例

ticket登录服务, 需要从cookie中获取到 fdidticket

调用原子操作 import user_login_with_ticket from ‘@dfeidao/atom-nodejs/msg/user-login-with-ticket’; , 传参fdid, ticket等

4.1 feidao.json添加路由配置项

{
	"url": "/ticket-login",
	"method": "get",
	"service": "dataservice.nodejs",
	"data": {
		"modelid": "atom/ticket-login-service"
	}
}

4.2 添加ticket登录服务 src/atom/ticket-login-service.ts

import logger from '@dfeidao/atom-nodejs/logger/log';
import user_login_with_ticket from '@dfeidao/atom-nodejs/msg/user-login-with-ticket';
import { IncomingHttpHeaders } from 'http';
import { spaceid } from './config';

interface Message {
	cookie: {
		fdid: string;
		ticket: string;
		sessionid: string;
		[key: string]: string;
	};
	urls: {
		base: string;
		origin: string;
		url: string;
	};
}

interface IWebResult {
	data: unknown;
	cookie?: {
		[name: string]: string;
	} | null;
	content_type?: string;
	headers?: {
		[key: string]: string;
	};
	attachment?: string;
	redirect?: string;
	status_code?: number;
}

export default async function atom(message: Message, action_id: string, session_id: string, headers: IncomingHttpHeaders): Promise<IWebResult> {
logger('Service begin path:atom/ticket-login,action_id:' + action_id);
	try {
		// 这里也可以对参数进行判断.参数缺失直接返回
		const fdid = message.cookie.fdid;
		const ticket = message.cookie.ticket;
		const user_info = await user_login_with_ticket(fdid, ticket, productid, spaceid, session_id, action_id);

		logger('Service end path:atom/ticket-login,action_id:' + action_id);
		return {
			data: 'success',
			cookie: {
				fdid,
				ticket: user_info.remember_me_ticket,
				sessionid: user_info.sessionID
			}
		};
	} catch (error) {
		logger(error.toString());
		// fdid或ticket无效 通过客户端参数没有找到对应的rememberMe信息
		// 参数remember_me_flag不可为空
		// 参数remember_me_ticket不可为空
		return {
			data: 'fail'
		};
	}
}