文章目录[x]
- 0.1:一、前言
- 0.2:二、流程
- 0.3:三、主要代码
- 0.4:四、总结
一、前言
使用Nodejs为unity程序做使用次数统计和授权登录。
这套系统分为三部分:1.Unity模块;2.Nodejs服务;3.管理页面。
二、流程
unity程序登录
- unity启动时向服务器请求是否可以登录。
- nodejs服务器查询是否存在该id,如果不存在则创建。
- nodejs服务器查询要登录的程序名称,如果不存在则返回登录失败。
- nodejs服务器查询当前程序是否可以登录,如果不能登录返回登录失败。
- nodejs服务器查询当前用户ID是否授权登录,如果没有授权返回登录失败。
- nodejs服务器向数据库插入当前用户的登录信息,返回运行登录。
管理页面
- 管理员登录。
- 查询用户登录记录,带搜索。
- 查询用户列表,并且可以修改单个用户的登录权限。
- 查询程序列表,并且可以修改单个程序的登录权限。
管理页面是用vue2开发的,主要使用的模块:vue-router,vuex,element-ui。
三、主要代码
- Unity LoginStats.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.Networking;
public class LoginStats : MonoBehaviour
{
public string ProgramName = "测试程序";
private string uuid = "uid";
private void Awake()
{
QueryClientInfo();
}
private void QueryClientInfo()
{
string storeId = PlayerPrefs.GetString(uuid, "");
if (string.IsNullOrEmpty(storeId))
{
storeId = Guid.NewGuid().ToString();
PlayerPrefs.SetString(uuid, storeId);
}
RequestAuth(storeId);
}
private void RequestAuth(string clientID)
{
StartCoroutine(APIRequest(clientID));
}
private IEnumerator APIRequest(string clientID)
{
WWWForm form = new WWWForm();
form.AddField("clientID", clientID);
form.AddField("programName", ProgramName);
UnityWebRequest req = UnityWebRequest.Post("https://5y5007l723.zicp.fun/api/clientLogin", form);
yield return req.SendWebRequest();
if (req.isNetworkError)
{
Debug.Log(req.error);
}
else
{
string res = req.downloadHandler.text;
Debug.Log(res);
if(!res.Contains("允许登录"))
{
Application.Quit();
}
}
}
}
- Nodejs登录接口
/**
* 客户端登陆接口
* params:clientID programName ip/mac
*/
router.post("/clientLogin", (req, res) => {
// var clientid = req.query.clientID;
// var programname = req.query.programName;
var clientid = req.body.clientID;
var programname = req.body.programName;
//如果使用了内网穿透,此处恒为127.0.0.1,如果前端使用了反向代理此处恒为127.0.0.1
var ip = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddres || req.socket.remoteAddress || '';
var info = {
clientid: clientid,
programname: programname,
ip: ip
}
let sql = "select * from clientinfo where clientID=?"
let arr = [info.clientid];
sqlFn(sql, arr, result => {
if (result.length > 0) {
//存在该客户端
var currentClient = result[0];
let sql = "select * from programinfo where programName=?"
let arr = [info.programname];
sqlFn(sql, arr, result => {
if (result.length > 0 && result[0].globalEntry == "true") {
//允许全局登陆
if (currentClient.allowLogin == "true") {
//该客户端允许登陆
res.send({ status: 200, msg: '允许登陆' })
writeLoginInfo(info.clientid, info.programname, info.ip)
}
else {
//该客户端不允许登陆
res.send({ status: 500, msg: '客户端不允许登陆' })
}
}
else {
//不允许全局登陆
res.send({ status: 500, msg: '未找到该程序或全局不允许登陆' })
}
})
}
else {
//不存在该客户端
let sql = "insert into clientinfo values(null,?,?,'','true')"
let arr = [info.clientid, info.ip];
sqlFn(sql, arr, result => {
if (result.affectedRows > 0) {
//添加新客户端成功
let sql = "select * from programinfo where programName=?"
let arr = [info.programname];
sqlFn(sql, arr, result => {
if (result.length > 0 && result[0].globalEntry == "true") {
//全局允许登陆
res.send({ status: 200, msg: '允许登陆' })
writeLoginInfo(info.clientid, info.programname, info.ip)
}
else {
//全局不允许登陆
res.send({ status: 500, msg: '全局不允许登陆' })
}
})
}
else {
//添加新客户端失败
res.send({ status: 500, msg: '客户端添加失败' })
}
})
}
})
})
四、总结
- 1.管理页面放在了云服务器并且使用了CDN加速,服务器放在了本地的虚拟机中,然后使用了免费的花生壳内网穿透。(会导致nodejs拿不到真正的客户IP,只能拿到花生壳也就是本机IP)
- 2.管理页面请求接口需要写完整服务器接口路径,如果管理页面中要隐藏服务器地址可以使用nginx做反向代理达到隐藏实际服务器IP的目的。
nginx设置反向代理示例:
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root C:\Users\A\Desktop\WebGLLocation;
index index.html index.htm;
}
#为vue设置代理 ’/api‘为请求的规则
# location /api {
# proxy_pass https://5y5007l723.zicp.fun;
# }
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}