HBuilder 打包 H5 APP 进行认证登录

2023-11-03

【H5 Mui】 App 统一身份认证登录过程的记录

在 h5 app 开发的过程中,用到到统一认证登录的功能(统一身份认证登接口),来进行登录验证。
在开发 h5 app 的时候,一般会提供 app 网页版的,这时候会发现,网页版和打包的APP几乎相同,都能满足需求。

在项目中有这样一个需求:每次评论检查是否登录,否则跳转统一的登录接口,之后在进行评论。这个需求前提是自己的项目大部分浏览不需要用户登录,且对用户账号的控制并不多,这时候一般采用别的更方便的接口或API来快速搭建需要登录的模块。

  • 遇到的问题:在网页版,认证登录等操作都是基于Web的,登录成功后跳转一切正常,但是打包的 apk 却存在问题,无法跳转和跳转后如何获取到登录成功后的 code (表示登录用户的查询码,用来查询是谁,表示这个用户的唯一授权,过期需要重新登录) 。
  • CODE 的保存与使用 ,中间可能会遇到跨域传值问题。

带着上面的问题,继续看看我实际遇到的问题与解决方案。

common.js APP的所有页面都引用这个 js

// 某 统一身份认证的接口
var login_url ="http://xxx.xxxxx.cn/login?client_id=2100&redirect_uri=http://xxx.xxx.xxx.xxx/app/pages/loginto.html&response_type=code&scope=user_info&state=&toonType=100"; 
// 上面的地址可分为几个部分
// 一、认证接口 :http://xxx.xxxxx.cn/login
// 二、客户端ID:client_id = 2100
// 三、认证成功跳转地址:redirect_uri = http://xxx.xxx.xxx.xxx/app/pages/loginto.html 
// 四、跳转后的附加参数:  &response_type=code&scope=user_info&state=&toonType=100
// 关于疑问:
// 第三项中,loginto.html 实质上是个中介页面,接受回调地址上的参数,显示“登录中正跳转”的提示
// 第四项中,包含很多关于API的控制,具体看认证接口

// code 的作用 一般是用来查询用户授权的信息(表示当前用户的唯一值)
function loginToken(code){
   if (!code) return;
   // app 去查询统一身份认证平台 的接口
   $.ajaxJSONP('xx.xxx/xxx?code='+code,false,function(response){
   		if (!response) return;
   		if (response["state"] == "success") {
   		window.token = response["token"];
   		// localStorage 全局变量中保存,h5 的 app 每一个页面都能访问到这个值
   		localStorage.setItem("token",window.token);
   	}
   });
}	

// 获取 Token 
function getToken(){
   var token="";
   if(window.token){
   		token = window.token;
   }else if(localStorage.getItem("token")){
   		token = localStorage.getItem("token");
   }else{
   		token =  commonjs.getOneUrlParams("token");
   }
   return token;
}

// 判断是否登录
function loginIn(){
   var token = getToken();
   if(!token) {
   		return false;
   }else {
   		return true;
   }
   // 也可以继续验证 token 是否有效
}

// 前往认证中心
function toAuth(){
   // 使用 mui 的方式 并设置不使用缓存 (打包 apk 使用缓存会出现问题)
   openwindow("login.html?random=" + Math.random(),{cachemode:"noCache"});
}

//跳转窗口
function openwindow(_url, _styles, _extras) {
   if(localStorage.getItem("token")) window.token = localStorage.getItem("token");
   window.token && (_url = _url + (_url.indexOf("?") == -1 ? "?" : "&") + "token=" + window.token);
   mui.openWindow({
   		url: _url,
   		id: _url,
   		styles: _styles ? _styles : {},
   		extras: _extras ? _extras : {}, //新窗口的额外扩展参数,可用来处理页面间传值
   		createNew: false,
   		show: {
   			autoShow: true
   		},
   		waiting: {
   			autoShow: true,
   			title: '正在加载...'
   		}
   })
}

有了上面这样大概的认证的方法后,继续看下面 login.html 页面 和 中介 页面 loginto.html 的关系。

  • login.html 页面 在 网页版 和 apk 版 是做为登录页面的外壳而设计的,用来接收子页面的传值,子页面放在一个Iframe中。
  • loginto.html 页面 无论 网页版 还是 apk 版 都是作为回调地址 和 中介页面设计的,用来登录后接收参数,并将 code 传递给 外层(谁装载了 loginto.html 谁就是外层)
  • 上面的操作设计到跨域传值问题,解决方案:Messenger.js 只要让中介 页面 和装载他的页面 都引用这个 js 使用几个简单的方法就能将值传递过去。

Messenger.js 跨域传值的工具 js 源文件 这部分文件源码是别人写的,拿来复制,省的上传文件丢了,或不愿了解它的内部原理

/**
 *     __  ___
 *    /  |/  /___   _____ _____ ___   ____   ____ _ ___   _____
 *   / /|_/ // _ \ / ___// ___// _ \ / __ \ / __ `// _ \ / ___/
 *  / /  / //  __/(__  )(__  )/  __// / / // /_/ //  __// /
 * /_/  /_/ \___//____//____/ \___//_/ /_/ \__, / \___//_/
 *                                        /____/
 *
 * @description MessengerJS, a common cross-document communicate solution.
 * @author biqing kwok
 * @version 2.0
 * @license release under MIT license
 */

window.Messenger = (function(){

    // 消息前缀, 建议使用自己的项目名, 避免多项目之间的冲突
    // !注意 消息前缀应使用字符串类型
    var prefix = "[PROJECT_NAME]",
        supportPostMessage = 'postMessage' in window;

    // Target 类, 消息对象
    function Target(target, name, prefix){
        var errMsg = '';
        if(arguments.length < 2){
            errMsg = 'target error - target and name are both required';
        } else if (typeof target != 'object'){
            errMsg = 'target error - target itself must be window object';
        } else if (typeof name != 'string'){
            errMsg = 'target error - target name must be string type';
        }
        if(errMsg){
            throw new Error(errMsg);
        }
        this.target = target;
        this.name = name;
        this.prefix = prefix;
    }

    // 往 target 发送消息, 出于安全考虑, 发送消息会带上前缀
    if ( supportPostMessage ){
        // IE8+ 以及现代浏览器支持
        Target.prototype.send = function(msg){
            this.target.postMessage(this.prefix + '|' + this.name + '__Messenger__' + msg, '*');
        };
    } else {
        // 兼容IE 6/7
        Target.prototype.send = function(msg){
            var targetFunc = window.navigator[this.prefix + this.name];
            if ( typeof targetFunc == 'function' ) {
                targetFunc(this.prefix + msg, window);
            } else {
                throw new Error("target callback function is not defined");
            }
        };
    }

    // 信使类
    // 创建Messenger实例时指定, 必须指定Messenger的名字, (可选)指定项目名, 以避免Mashup类应用中的冲突
    // !注意: 父子页面中projectName必须保持一致, 否则无法匹配
    function Messenger(messengerName, projectName){
        this.targets = {};
        this.name = messengerName;
        this.listenFunc = [];
        this.prefix = projectName || prefix;
        this.initListen();
    }

    // 添加一个消息对象
    Messenger.prototype.addTarget = function(target, name){
        var targetObj = new Target(target, name,  this.prefix);
        this.targets[name] = targetObj;
    };

    // 初始化消息监听
    Messenger.prototype.initListen = function(){
        var self = this;
        var generalCallback = function(msg){
            if(typeof msg == 'object' && msg.data){
                msg = msg.data;
            }
            
            var msgPairs = msg.split('__Messenger__');
            var msg = msgPairs[1];
            var pairs = msgPairs[0].split('|');
            var prefix = pairs[0];
            var name = pairs[1];

            for(var i = 0; i < self.listenFunc.length; i++){
                if (prefix + name === self.prefix + self.name) {
                    self.listenFunc[i](msg);
                }
            }
        };

        if ( supportPostMessage ){
            if ( 'addEventListener' in document ) {
                window.addEventListener('message', generalCallback, false);
            } else if ( 'attachEvent' in document ) {
                window.attachEvent('onmessage', generalCallback);
            }
        } else {
            // 兼容IE 6/7
            window.navigator[this.prefix + this.name] = generalCallback;
        }
    };

    // 监听消息
    Messenger.prototype.listen = function(callback){
        var i = 0;
        var len = this.listenFunc.length;
        var cbIsExist = false;
        for (; i < len; i++) {
            if (this.listenFunc[i] == callback) {
                cbIsExist = true;
                break;
            }
        }
        if (!cbIsExist) {
            this.listenFunc.push(callback);
        }
    };
    // 注销监听
    Messenger.prototype.clear = function(){
        this.listenFunc = [];
    };
    // 广播消息
    Messenger.prototype.send = function(msg){
        var targets = this.targets,
            target;
        for(target in targets){
            if(targets.hasOwnProperty(target)){
                targets[target].send(msg);
            }
        }
    };

    return Messenger;
})();

login.html 统一身份认证登录的外壳页面

<!DOCTYPE html>
<html>
   <head>
   		<title>登录</title>
   </head>
   <body>
   		<iframe id="login"  src="" ></iframe>
   		<script src="../js/mui.min.js"></script>
   		<!-- 其他JS 引用 包括 Messenger.js Common.js -->
   		<script type="text/javascript">
   			var messenger = new Messenger('parent', 'monitor');
   			var login = document.getElementById('login');
   			login.src = login_url; // 转载登录页面
   			messenger.listen(function (msg) {
   				// 登录成功后 中介页面会调用 Messenger 的方法传值 ,这里就进行接收。
   		        loginToken(msg);	// 根据 code 获取 token 
   		        openwindow("home.html?random=" + Math.random(),{cachemode:"noCache"}); // 回到你想回到的地方
   		    });
   		</sctipt>
   </body>
</html>

loginto.html 登录的中介页面 这个是网络页面,apk 用来跳转本地页面准备的

<!DOCTYPE html>
<html>
	<head>
			<title>登录跳转</title>
	</head>
	<body>
		<!-- 显示其他动画 -->
		<!-- 其他JS 引用 包括 Messenger.js  -->
		<script type="text/javascript">
			var messenger = new Messenger('login', 'monitor');
			messenger.addTarget(window.parent, "parent");
			if(parent!=window) {
				var msg = window.location.search;
				if(msg){
					msg = msg.split("code=")[1].split("&")[0];
					// 先外层传值
					messenger.targets["parent"].send(msg);
				} 
			}
		</sctipt>
	</body>
</html>

在进行登录时:

  • 首先会跳转到 login.html 页面,这时候 Iframe 装载的是统一身份认证的登录页,它的域不外层域内。

登录成功时:

  • Iframe 登录页 自动跳转 loginto.html ,这时的 Iframe 装载的是网络版的 中介页面而且,url 也会带有登录成功的 code 。

中介页面传值:

  • loginto.html 把 url 中的 code ,传递给外层,他的工能就完成了。

外层页面接收值:

  • code 传入后保存起来,这里外层就是你登录前的那个域内,跳转后的其它页面获取到 token 就算成功!。

注意 如果 apk 版直接跳转统一认证页面,登录成功后可能就跳转到网页版的域中,后续使用的文件全部都是 网络获取 ,而不是本地文件,这之后出现的问题都是网页版的,如果没有跳转成功,可能是 apk 的配置或者跳转方式有问题,有可能是缓存,也有可能是限制或禁止,会导致 登录后的 token 获取不到。

如有误导请联系,我会进行修正。
邮箱 hbck_gwx@qq.com

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HBuilder 打包 H5 APP 进行认证登录 的相关文章

随机推荐

  • 【概率论】先验概率、联合概率、条件概率、后验概率、全概率、贝叶斯公式

    参考 浅谈全概率公式和贝叶斯公式 先验概率 先验概率是基于背景常识或者历史数据的统计得出的预判概率 一般只包含一个变量 例如P A P B 联合概率 联合概率指的是事件同时发生的概率 例如现在A B两个事件同时发生的概率 记为P A B P
  • Linux系统(Centos7)部署JDK环境

    要想在将Java项目上线 则必须在Linux系统中部署Java项目 而要想Java项目在Linux系统中运行 则首先必须在LInux系统中部署JDK环境 具体步骤如下所示 1 下载JDK8 JDK下载路径 目前官网下载jdk的时候需要登录
  • python解析tcp数据包-python解析获取发往本机的数据包并打印

    1 文件 tcp py 2KB 下载 69 coding cp936 import socket from struct import from time import ctime sleep from os import system s
  • Java中输入一个整数n,实现n的阶乘

    n的阶乘 1 2 3 n public static void main String args 2 输入一个整数n 实现n的阶乘 n n 1 1 Scanner sc new Scanner System in System out pr
  • git push origin master和git push的区别

    目录 1 git push origin master 指定远程仓库名和分支名 2 git push 不指定远程仓库名和分支名 3 这两者的区别 git push是git push origin master的一种简写形式 4 建议使用 g
  • 原代码阅读与分析

    服务计算web技术之原代码阅读与分析 先给出分析代码的链接 mux go 路由Router 创建Router实例 type Router struct Configurable Handler to be used when no rout
  • 编译原理实验 实验二 LL(1)分析法 Python实现

    1 实验目的 通过完成预测分析法的语法分析程序 了解预测分析法和递归子程序法的区别和联系 使学生了解语法分析的功能 掌握语法分析程序设计的原理和构造方法 训练学生掌握开发应用程序的基本方法 有利于提高学生的专业素质 为培养适应社会多方面需要
  • python更换版本。

    问题背景 由于ddddocr库需要python3 9及以下的版本 本人安装的为python3 11版本 所以需要更换版本 解决办法 1 安装所需要版本的pyhton我安装的是python3 9 之前安装的python3 11是不需要卸载的
  • 机器学习笔记(一):监督学习与无监督学习概述

    机器学习的两种模型 监督学习和无监督学习 一 监督学习 supervised learning 监督学习是实际应用中使用更多的机器学习类型 1 监督学习就是学习从x到y 即学习从输入到输出的映射的算法 关键特征就是提供学习算法的实例供机器学
  • Microsoft Dynamics CRM 2015 之安装SQL Server 2012过程中出现“启用windows功能NetFx3时出错...

    错误详细信息 安装 Microsoft NET Framework 3 5 时出错 启用 Windows 功能 NetFx3 时出错 错误代码 2146498298 请尝试从 Windows 管理工具启用 Windows 功能 NetFx3
  • LeetCode日记

    题目 实现 strStr 函数 给定一个 haystack 字符串和一个 needle 字符串 在 haystack 字符串中找出 needle 字符串出现的第一个位置 从0开始 如果不存在 则返回 1 说明 当 needle 是空字符串时
  • html input date不起效,JavaScript – HTML 5 input type =“date”在Firefox中不起作用

    Firefox doesn t support HTML5 s 你有两个选择 gt 总是使用Javascript日期时间选择器 或 gt 检查浏览器是否支持该标签 如果是使用它 如果没有 然后回退在javascript datepicker
  • frida启动报错:./frida-server-15.1.27-android-x86_64: can‘t execute: Is a directory

    报错场景 在MuMu模拟器上安装frida server 启动的时候报错 报错信息如下 frida server 15 1 27 android x86 64 can t execute Is a directory 原因剖析 报错信息上显
  • 10g r2 RAC Dataguard 3 nodes

    最近在深圳实施windows 2003 上的oracle RAC项目 原来计划是两个节点 结果客户要求三个节点 因为是他们认为购买的服务器只有二个cpu 原来计划是四个cpu 然后还要在做dataguard 一开始安装很顺利 两个节点测试也
  • HTTP状态 405 - 方法不允许

    错误描述 HTTP状态 405 方法不允许 类型 状态报告 消息 Request method GET not supported 描述 请求行中接收的方法由源服务器知道 但目标资源不支持 此时的原因是请求类型错误 网页是get请求 但是实
  • springMVC项目如何配置tomcat

    先打开项目然后按图片所示操作 最后点击ok就可以启动项目啦
  • 【机器学习教程】四、随机森林:从论文到实践

    引言 随机森林 Random Forest 是机器学习领域中一种强大的集成学习算法 它的优秀性能和广泛应用使得它成为了机器学习领域的一个重要里程碑 本文将从算法的发展历程 重要论文 原理以及实际应用等方面详细介绍随机森林 并提供一个复杂的实
  • 时间段随机 java_java生成指定范围的随机日期

    有这样一个需求 构造一个方法 随机生成1990 12 31 00 00 00到 2013 12 31 00 00 00之间任意一个时间点 思路是这样 在javaAPI中 Date类型和long类型很好转化 所以我们可以把问题转化为 求两个l
  • Selinux

    1 Selinux的影响 对于文件的影响 当selinux开启时 内核会对每个文件及每个开启的程序进行标签加载 标签内记录程序和文件的安全上下文 context 对于程序功能的影响 当selinux开启会对程序的功能加载开关 并设定此开关的
  • HBuilder 打包 H5 APP 进行认证登录

    H5 Mui App 统一身份认证登录过程的记录 在 h5 app 开发的过程中 用到到统一认证登录的功能 统一身份认证登接口 来进行登录验证 在开发 h5 app 的时候 一般会提供 app 网页版的 这时候会发现 网页版和打包的APP几