系統端部分程式需要客製修改.
設定-01 : 網頁檔使用的副檔名.
mint_aam/maam_build/maam_custom.c
// 分別是副檔名的名稱和長度, 如果不是則需要修改.
#define MAAM_HTML_KEY ".html"
#define MAAM_HTML_LEN 5
設定-02 : 登入頁面和登入後主要頁面的路徑.
mint_aam/maam_build/maam_custom.c
// 以 mini_httpd.conf 中 dir=... 的位置為基準.
#define MAAM_PAGE_LOGIN "/login.html"
#define MAAM_PAGE_INDEX "/index.html"
設定-03 : 在 GET 時, 哪些網頁不用登入也允許讀取 (例如登入頁面).
列表 :
mint_aam/maam_build/maam_custom.c
struct maam_access_t maam_access_allow_get_html_list[] =
{
{MAAM_PAGE_LOGIN, 0, MAAM_CACCESS_ALL, NULL, 0, 0},
{NULL, 0, 0, NULL, 0, 0}
};
[struct maam_access_t maam_access_allow_get_html_list[]]
結構成員
char *
cmp_path_con
|
要和路徑部分 (path) 比對的字串
|
size_t
cmp_path_len
|
cmp_path_con 的長度
|
size_t
cmp_path_method
|
要和路徑部分比對的方法
MAAM_COMPARE_ACCESS_METHOD
(mint_aam/mcm_lib/maam_buildin/maam_local.h)
|
| MAAM_CACCESS_NONE |
不比對, 直接認定匹配.
(使用此方法 cmp_path_con, cmp_path_len) 無作用
|
| MAAM_CACCESS_ALL |
路徑部分和比對的字串需要完全相同
(使用此方法 cmp_path_len) 無作用
|
| MAAM_CACCESS_PREFIX |
路徑部分的頭部往後 cmp_path_len
個字元需要和比對的字串相同
|
| MAAM_CACCESS_POSTFIX |
路徑部分的尾部往前 cmp_path_len
個字元需要和比對的字串相同
|
| MAAM_CACCESS_SUB |
比對部分的字串是路徑部分的子字串
(使用此方法 cmp_path_len) 無作用
|
|
char *
cmp_query_con
|
要和查詢部分 (query) 比對的字串
|
size_t
cmp_query_len
|
cmp_query_con 的長度
|
size_t
cmp_query_method
|
要和 GET 的查詢部分比對的方法
MAAM_COMPARE_ACCESS_METHOD
(mint_aam/mcm_lib/maam_buildin/maam_local.h)
|
| MAAM_CACCESS_NONE |
不比對, 直接認定匹配.
(使用此方法 cmp_query_con, cmp_query_len) 無作用
|
| MAAM_CACCESS_ALL |
查詢部分和比對的字串需要完全相同
(使用此方法 cmp_query_len) 無作用
|
| MAAM_CACCESS_PREFIX |
查詢部分的頭部往後 cmp_query_len
個字元需要和比對的字串相同
|
| MAAM_CACCESS_POSTFIX |
查詢部分的尾部往前 cmp_query_len
個字元需要和比對的字串相同
|
| MAAM_CACCESS_SUB |
比對的字串是查詢部分的子字串
(使用此方法 cmp_query_len) 無作用
|
|
注意事項 :
| 01. |
cmp_query_con 設 NULL 表示不比對查詢部分.
|
| 02. |
會先處理先 cmp_path_con, 成立才會處理 cmp_query_con.
|
|
注意事項 :
| 01. |
至少要填登入網頁.
|
| 02. |
最後一組必須是 {NULL, 0, 0, NULL, 0, 0}.
|
| 03. |
未登入時讀取非允許的網頁檔會重導向到登入頁面.
|
範例 :
struct maam_access_t maam_access_allow_get_html_list[] =
{
// 網頁 "/login.html" 允許存取.
{MAAM_PAGE_LOGIN, 0, MAAM_CACCESS_ALL, NULL, 0, 0},
// 目錄 "/debug/" 以下的網頁允許存取.
{"/debug/", 7, MAAM_CACCESS_PREFIX, NULL, 0, 0},
// 檔名結尾是 "guest.html" 的網頁允許存取.
{"guest.html", 10, MAAM_CACCESS_POSTFIX, NULL, 0, 0},
// 不管存取的網頁為何, GET 的查詢字串中帶有 "open" 關鍵字就允許存取.
{"", 0, MAAM_CACCESS_NONE, "open", 0, MAAM_CACCESS_SUB},
{NULL, 0, 0, NULL, 0, 0}
};
設定-04 : 瀏覽器在 GET 時, 哪些非網頁檔在未登入情況下禁止存取.
預設情況下, 在還沒登入時 GET 非網頁檔是允許的 (如 CSS, JS, 圖片檔等等),
可以設定哪些檔案登入後才能存取.
列表 :
mint_aam/maam_build/maam_custom.c
struct maam_access_t maam_access_deny_get_other_list[] =
{
{NULL, 0, 0, NULL, 0, 0}
};
設定方法和 maam_access_allow_get_html_list[] 一樣
[詳細].
注意事項 :
| 01. |
最後一組必須是 {NULL, 0, 0, NULL, 0, 0}.
|
| 02. |
還沒登入就存取禁止的非網頁檔會回傳 HTTP 404.
|
範例 :
struct maam_access_t maam_access_allow_get_html_list[] =
{
// 系統的設定檔 "/system.cfg" 登入後才能下載.
{"/system.cfg", 11, MAAM_CACCESS_ALL, NULL, 0, 0},
{NULL, 0, 0, NULL, 0, 0}
};
設定-05 : 在 POST 時, 哪些項目不用登入也允許使用.
列表 :
mint_aam/maam_build/maam_custom.c
struct maam_access_t maam_access_allow_post_list[] =
{
{NULL, 0, 0, NULL, 0, 0}
};
設定方法和 maam_access_allow_get_html_list[] 一樣
[詳細].
注意事項 :
| 01. |
最後一組必須是 {NULL, 0, 0, NULL, 0, 0}.
|
| 02. |
還沒登入就使用禁止的項目會回傳導向登入頁面的 JavaScript 程式.
|
範例 :
struct maam_access_t maam_access_allow_post_list[] =
{
// 使用 "/cgi/mcm_cgi_config.cgi" 存取設定時, 如果查詢字串的尾端有 "anyone" 關鍵字就允許使用.
{"/cgi/mcm_cgi_config.cgi", 0, MAAM_CACCESS_ALL, "anyone", 6, MAAM_CACCESS_POSTFIX},
{NULL, 0, 0, NULL, 0, 0}
};
設定-06 : 實作帳號驗證部分.
函式 :
mint_aam/maam_build/maam_custom.c
int maam_verify_account(
struct maam_login_t *login_info,
int *verify_result_buf)
{
int fret = MAAM_RCODE_PASS, cret = MAAM_RCODE_INTERNAL_ERROR;
...
*verify_result_buf = cret;
return fret;
}
參數的用途 :
| 參數 |
說明 |
struct maam_login_t *
login_info
|
登入的資料以及建立 session 需要的資料, 登入的資料部分用來做帳號驗證,
session 需要的資料需要在帳號驗證成功後給予
|
int *
verify_result_buf
|
紀錄帳號驗證是否成功的緩衝
|
[struct maam_login_t *login_info]
結構成員
usockaddr *
client_addr
|
登入的資料, 客戶端的位址
|
char *
verify_name
|
登入的資料, 帳號名稱
|
char *
verify_password
|
登入的資料, 帳號密碼
|
char
account_name[MAAM_BSIZE_ACCOUNT_NAME]
|
session 需要的資料, 帳號名稱
|
int
account_permission
|
session 需要的資料, 帳號的權限 (值越小代表越高)
|
long
account_idle_timeout
|
session 需要的資料, 帳號的閒置超時時間
|
[fret]
用來表示處理帳號驗證時是否發生問題, 例如透過 MintCM 取得帳號資料時, 函數呼叫發生錯誤.
可以設定的值 :
|
MAAM_RCODE_PASS
|
處理過程沒有發生錯誤
|
|
< MAAM_RCODE_PASS
|
處理過程發生錯誤
|
[cret]
用來表示帳號名稱和帳號密碼是否正確.
可以設定的值 :
|
MAAM_RCODE_PASS
|
帳號正確
|
|
MAAM_RCODE_INVALID_ACCOUNT_NAME
|
帳號名稱錯誤
|
|
MAAM_RCODE_INVALID_ACCOUNT_PASSWORD
|
帳號密碼錯誤
|
如果網頁端傳送的是加密後的資料, 在系統端也需要先將帳號資料加密後在比對.
maam_md5_hash
將資料做 MD5 加密.
| 參數 |
說明 |
void *
data_con
|
要加密的資料 |
size_t
data_len
|
要加密的資料的長度 |
char *
out_buf
|
紀錄小寫字串格式的加密結果的緩衝 |
size_t
out_size
|
out_buf 的大小 |
|
範例 :
int maam_verify_account(
struct maam_login_t *login_info,
int *verify_result_buf)
{
int fret = MAAM_RCODE_PASS, cret = MAAM_RCODE_INTERNAL_ERROR;
// 紀錄 MD5 加密後的字串的緩衝.
char hash_code[MAAM_BSIZE_MD5_HASH];
// 存取 MintCM 需要的資料.
char *path1, path2[MCM_PATH_MAX_LENGTH];
struct mcm_lulib_lib_t self_lulib;
struct mcm_dv_device_web_account_t account_v;
MCM_DTYPE_EK_TD account_count, i;
// 使用 MintCM.
// device.web.account.* 紀錄帳號的資料.
self_lulib.socket_path = "@mintcm";
self_lulib.call_from = MCM_CFROM_USER;
self_lulib.session_permission = MCM_SPERMISSION_RO;
self_lulib.session_stack_size = 0;
if(mcm_lulib_init(&self_lulib) < MCM_RCODE_PASS)
{
MAAM_EMSG("call mcm_lulib_init() fail");
fret = MAAM_RCODE_INTERNAL_ERROR;
goto FREE_01;
}
// 讀出 device.web.account.* 的資料筆數.
path1 = "device.web.account.*";
if(mcm_lulib_get_count(&self_lulib, path1, &account_count) < MCM_RCODE_PASS)
{
MAAM_EMSG("call mcm_lulib_get_count(%s) fail", path1);
fret = MAAM_RCODE_INTERNAL_ERROR;
goto FREE_02;
}
// 網頁端傳送的帳號名稱和帳號密碼都經過 MD5 加密, 所以這邊也需要先對資料加密在比對.
for(i = 0; i < account_count; i++)
{
// 讀出帳號資料.
snprintf(path2, sizeof(path2), "device.web.account.@" MCM_DTYPE_EK_PF, i + 1);
if(mcm_lulib_get_entry(&self_lulib, path2, &account_v) < MCM_RCODE_PASS)
{
MAAM_EMSG("call mcm_lulib_get_entry(%s) fail", path2);
fret = MAAM_RCODE_INTERNAL_ERROR;
goto FREE_02;
}
// 使用 MD5 處理帳號名稱並比對.
maam_md5_hash(account_v.name, strlen(account_v.name),
hash_code, sizeof(hash_code));
if(strcmp(login_info->verify_name, hash_code) == 0)
{
// 使用 MD5 處理帳號密碼並比對.
maam_md5_hash(account_v.password, strlen(account_v.password),
hash_code, sizeof(hash_code));
if(strcmp(login_info->verify_password, hash_code) == 0)
{
// 帳號名稱和帳號密碼都正確.
MAAM_BDMSG("login pass [%s]", account_v.name);
break;
}
else
{
// 帳號密碼錯誤.
MAAM_BDMSG("login fail [%s], invalid password", account_v.name);
cret = MAAM_RCODE_INVALID_ACCOUNT_PASSWORD;
goto FREE_02;
}
}
}
if(i >= account_count)
{
// 帳號名稱錯誤.
MAAM_BDMSG("login fail, invalid name");
cret = MAAM_RCODE_INVALID_ACCOUNT_NAME;
goto FREE_02;
}
// 驗證成功, 填充 session 需要的資料.
snprintf(login_info->account_name, sizeof(login_info->account_name), "%s", account_v.name);
login_info->account_permission = account_v.permission;
login_info->account_idle_timeout = account_v.idle_timeout;
// 設定帳號驗證正確.
cret = MAAM_RCODE_PASS;
FREE_02:
mcm_lulib_exit(&self_lulib);
FREE_01:
*verify_result_buf = cret;
return fret;
}
上述是基本的修改, 另外還有一些額外的部分視需要才要修改.
額外-01 : 共享記憶體的 key 值.
session 的資料會放在共享記憶體內, key 值定義在 :
mint_aam/maam_build/maam_common.h
#define MAAM_SHARE_MEMORY_KEY 518276493
額外-02 : 共享記憶體的檔案互斥鎖的路徑 (此路徑必須可讀寫檔案).
存取 session 的資料必須使用互斥鎖保護避免多程式同時存取, 這邊使用 flock() 做為互斥鎖 :
mint_aam/maam_build/maam_common.h
#define MAAM_MUTEX_PATH "/var/run/maam_mutex"
額外-03 : 最大的 session 數目.
最大允許的已登入的使用者數目, 定義在 :
mint_aam/maam_build/maam_common.h
#define MAAM_MAX_SESSION 8
額外-04 : 權限的比對方式.
在比對權限時
[詳細], 數值越低權限越高,
可以修改比對方式, 定義在 :
mint_aam/maam_build/maam_handle.c
// A 的權限是否高於等於 B.
#define MAAM_PERMISSION_HEIGHT_EQUAL(a, b) ((a) <= (b))
// A 的權限是否等於 B.
#define MAAM_PERMISSION_EQUAL(a, b) ((a) == (b))
// A 的權限是否低於 B.
#define MAAM_PERMISSION_LOW(a, b) ((a) > (b))