menu_res_auth_mgr.cpp
5.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include "stdafx.h"
#include "etradeclient/utility/menu_res_auth_mgr.h"
#include <sstream>
#include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include "etradeclient/browser/session.h"
#include "etradeclient/utility/logging.h"
#include "etradeclient/utility/string_converter.h"
#include "etradeclient/utility/openssl_aes_cbc.h"
#include "etradeclient/utility/application_config.h"
#include "etradeclient/utility/url_config.h"
#include "etradeclient/utility/win_http.h"
#include "etradeclient/boost_patch/property_tree/json_parser.hpp" // WARNIING! Make sure to include our patched version.
namespace PT = boost::property_tree;
namespace fs = boost::filesystem;
// For those menu item which are not configured by server side, we call them local menu resources,
// and we define their "auth_id" as 0 in config file. These menu items are authorized by default("is_authorized == true").
// For those menu items whose "auth_id" are not defined as 0 in config file,
// their authorization needs to be configured by server side, thus they are unauthorized by default("is_authorized == false").
static const uint32_t LOCAL_MENU_RES_AUTH_ID = 0;
struct MenuAuthItem
{
uint32_t id;// Menu Auth ID, defined by server side. If not authorized by server, value is 0.
std::string url_path; // Defined by server side. If not authorized by server, value is "".
std::wstring remark; // Defined by server side. If not authorized by server, value is "".
};
bool MenuResAuthMgr::UpdateAuth()
{
try
{
ReadMenuResAuthCfg(); // 1st, read menu res id and auth id config from config file.
DoUpdateAuth(RequestAuthInfo()); // Then request auth info from server and update the authorization of every menu.
}
catch (std::exception& ex)
{
LOG_FATAL(L"获取用户权限失败: " + gbk_2_wstr(ex.what()));
return false;
}
return true;
}
const MenuResAuthMgr::MenuItemsType& MenuResAuthMgr::MenuItems() const
{
return m_menu_items;
}
bool MenuResAuthMgr::IsLocalMenuItem(uint32_t menu_res_id) const
{
return LOCAL_MENU_RES_AUTH_ID == m_menu_items.at(menu_res_id).auth_id;
}
void MenuResAuthMgr::ReadMenuResAuthCfg()
{
try
{
const std::string kMenuBarConfEncryptFile("./Config/menu_res_auth_cfg");
#ifdef _DEBUG
// 在调试的时候,先生成加密文件
const std::string kMenuBarConfJsonFile("./Config/menu_res_auth_cfg.json");
AES_CBC::EncryptFileToFile(kMenuBarConfJsonFile, kMenuBarConfEncryptFile);
#endif
std::stringstream ss;
ss << AES_CBC::DecryptFromFile(kMenuBarConfEncryptFile);
//Parse the configuration file
PT::ptree ptree;
PT::read_json(ss, ptree);
for (const auto& elem : ptree)
{
MenuItem menu_item;
menu_item.icon_name = elem.second.get<std::string>("icon");
menu_item.auth_id = elem.second.get<uint32_t>("auth_id");
menu_item.is_authorized = (menu_item.auth_id == LOCAL_MENU_RES_AUTH_ID) ? true : false;
menu_item.url_path = ""; // Empty by default.
menu_item.remark = L""; // Empty by default.
PT::ptree menu_index_list = elem.second.get_child("index");
for (const auto& elem_ : menu_index_list)
{
menu_item.index_list.emplace_back(elem_.second.get_value<uint32_t>());
}
m_menu_items.emplace(std::make_pair(elem.second.get<uint32_t>("res_id"), menu_item));
}
}
catch (...)
{
throw std::exception("解析菜单资源配置文件出错!");
}
}
std::string MenuResAuthMgr::RequestAuthInfo() const
{
std::string auth_url = URLConfig::Instance().MenuAuthPath();
const uint32_t kHTTPOK = 200;
auto& url_cfg = URLConfig::Instance();
WinHttp win_http;
win_http.ConnectHost(url_cfg.Host(), url_cfg.Port(), url_cfg.IsHttps());
auto& request = win_http.OpenRequest(WinHttp::Method::GET, auth_url);
if (url_cfg.IsHttps())
{
auto& app_cfg = ApplicationConfig::Instance();
request.SetClientCertificate(app_cfg.ClientCertStore(), app_cfg.ClientCertSubject());
}
request.SetCookies(Session::Instance().Cookies());
request.Send();
uint32_t status_code = request.GetResponseStatus();
if (kHTTPOK != status_code)
{
std::string err_msg = "网络请求错误! 错误码: " + std::to_string(status_code);
throw std::exception(err_msg.c_str());
}
std::string response_body = request.ReadResponseBody();
if (response_body.empty())
throw std::exception("获取服务器响应数据失败,请确保网络连接正常");
return response_body;
}
void MenuResAuthMgr::DoUpdateAuth(const std::string& auth_data)
{
std::vector<MenuAuthItem> menu_auth_items;
try // Parse the auth data which is JSON format.
{
PT::ptree ptree;
std::stringstream ss; // boost::property_tree::read_json ask for non-const stringstream, don't ask me why, boost asks for this.
ss << auth_data;
PT::read_json(ss, ptree);
for (const auto& elem : ptree)
{
MenuAuthItem auth_item;
auth_item.id = elem.second.get<uint32_t>("code");
auth_item.url_path = elem.second.get<std::string>("path");
auth_item.remark = str_2_wstr(elem.second.get<std::string>("name"));
menu_auth_items.emplace_back(auth_item);
}
}
catch (...)
{
throw std::exception("解析服务器返回的授权菜单资源信息时出错!请确认返回数据不为空,返回的数据格式为正确的Json格式!");
}
for (auto& auth_item : menu_auth_items)
{
MenuItemsType::iterator it = std::find_if(m_menu_items.begin(), m_menu_items.end(),
[&auth_item](MenuItemsType::value_type& x)
{
return x.second.auth_id == auth_item.id;
});
if (it != m_menu_items.end()) // If authorized by server, update its information.
{
it->second.is_authorized = true;
it->second.url_path = auth_item.url_path;
it->second.remark = auth_item.remark;
it->second.iRename = 0;
}
}
//为了可恶的刚哥坑爹的设计而改动,他为了方便不给我一级菜单让我自己根据二级菜单找······
for (auto iterChild = m_menu_items.begin(); iterChild != m_menu_items.end(); ++iterChild)
{
for (auto iterDad = m_menu_items.begin(); iterDad != m_menu_items.end(); ++iterDad)
{
if (iterChild->second.is_authorized && iterChild->second.auth_id / 100 == iterDad->second.auth_id)
{
iterDad->second.is_authorized = true;
iterDad->second.url_path = "#";
}
}
}
//
}