mirror of
https://gitee.com/dgiiot/dgiot.git
synced 2024-11-29 18:57:41 +08:00
feat: add dlink auth
This commit is contained in:
parent
5a92781954
commit
3729770a5e
@ -8,10 +8,10 @@ parse.delete_field = ACL,objectId,updatedAt,createdAt
|
|||||||
##--------------------------------------------------------------------
|
##--------------------------------------------------------------------
|
||||||
parse.parse_server = http://prod.iotn2n.com:1337
|
parse.parse_server = http://prod.iotn2n.com:1337
|
||||||
parse.parse_path = /parse/
|
parse.parse_path = /parse/
|
||||||
parse.parse_appid = 49aa5a778d7ad75444d6ec010df4c633
|
parse.parse_appid = d3300b6f53d7ee7da766142f2f7050eb
|
||||||
parse.parse_master_key = 44f4052cae56b51e097420d23844a6ef
|
parse.parse_master_key = 3d9707db9414c4e398c5036ddb1b2b62
|
||||||
parse.parse_js_key = 7f2cf7f9ee16fabfe48cc48feed72347
|
parse.parse_js_key = fc8f19e9dcc4b8b7848aed1f8dcda317
|
||||||
parse.parse_rest_key = 35f51e718318f432a41e8bd9453f0c03
|
parse.parse_rest_key = 7957b8a5923c8be145b317521b922b18
|
||||||
|
|
||||||
##--------------------------------------------------------------------
|
##--------------------------------------------------------------------
|
||||||
## parse cache
|
## parse cache
|
||||||
|
@ -45,18 +45,16 @@ load_device(Order) ->
|
|||||||
|
|
||||||
post(Device) ->
|
post(Device) ->
|
||||||
DeviceId = maps:get(<<"objectId">>, Device),
|
DeviceId = maps:get(<<"objectId">>, Device),
|
||||||
DeviceName = maps:get(<<"name">>, Device),
|
|
||||||
Devaddr = maps:get(<<"devaddr">>, Device),
|
Devaddr = maps:get(<<"devaddr">>, Device),
|
||||||
Product = maps:get(<<"product">>, Device),
|
Product = maps:get(<<"product">>, Device),
|
||||||
ProductId = maps:get(<<"objectId">>, Product),
|
ProductId = maps:get(<<"objectId">>, Product),
|
||||||
<<DeviceSecretdefult:10/binary, _/binary>> = dgiot_utils:to_md5(dgiot_utils:random()),
|
DeviceSecret = maps:get(<<"deviceSecret">>, Device, <<"DeviceSecretdefault">>),
|
||||||
DeviceSecret = maps:get(<<"deviceSecret">>, Device, DeviceSecretdefult),
|
|
||||||
Status =
|
Status =
|
||||||
case maps:get(<<"status">>, Device, <<"OFFLINE">>) of
|
case maps:get(<<"status">>, Device, <<"OFFLINE">>) of
|
||||||
<<"OFFLINE">> -> false;
|
<<"OFFLINE">> -> false;
|
||||||
_ -> true
|
_ -> true
|
||||||
end,
|
end,
|
||||||
dgiot_mnesia:insert(DeviceId, {[Status, dgiot_datetime:now_secs(), get_acl(Device), DeviceName, Devaddr, ProductId, DeviceSecret], node()}).
|
dgiot_mnesia:insert(DeviceId, {[Status, dgiot_datetime:now_secs(), get_acl(Device), Devaddr, ProductId, DeviceSecret], node()}).
|
||||||
|
|
||||||
put(Device) ->
|
put(Device) ->
|
||||||
DeviceId = maps:get(<<"objectId">>, Device),
|
DeviceId = maps:get(<<"objectId">>, Device),
|
||||||
@ -75,12 +73,11 @@ put(Device) ->
|
|||||||
|
|
||||||
save(Device) ->
|
save(Device) ->
|
||||||
DeviceId = maps:get(<<"objectId">>, Device),
|
DeviceId = maps:get(<<"objectId">>, Device),
|
||||||
DeviceName = maps:get(<<"name">>, Device, <<"">>),
|
|
||||||
Devaddr = maps:get(<<"devaddr">>, Device),
|
Devaddr = maps:get(<<"devaddr">>, Device),
|
||||||
Product = maps:get(<<"product">>, Device),
|
Product = maps:get(<<"product">>, Device),
|
||||||
ProductId = maps:get(<<"objectId">>, Product),
|
ProductId = maps:get(<<"objectId">>, Product),
|
||||||
<<DeviceSecretdefult:10/binary, _/binary>> = dgiot_utils:to_md5(dgiot_utils:random()),
|
<<DeviceSecretdefult:10/binary, _/binary>> = dgiot_utils:to_md5(dgiot_utils:random()),
|
||||||
DeviceSecret = maps:get(<<"deviceSecret">>, Device, DeviceSecretdefult),
|
DeviceSecret = maps:get(<<"devicesecret">>, Device, DeviceSecretdefult),
|
||||||
UpdatedAt =
|
UpdatedAt =
|
||||||
case maps:get(<<"updatedAt">>, Device, dgiot_datetime:now_secs()) of
|
case maps:get(<<"updatedAt">>, Device, dgiot_datetime:now_secs()) of
|
||||||
<<Data:10/binary, "T", Time:8/binary, _/binary>> ->
|
<<Data:10/binary, "T", Time:8/binary, _/binary>> ->
|
||||||
@ -92,7 +89,7 @@ save(Device) ->
|
|||||||
<<"OFFLINE">> -> false;
|
<<"OFFLINE">> -> false;
|
||||||
_ -> true
|
_ -> true
|
||||||
end,
|
end,
|
||||||
dgiot_mnesia:insert(DeviceId, {[Status, UpdatedAt, get_acl(Device), DeviceName, Devaddr, ProductId, DeviceSecret], node()}).
|
dgiot_mnesia:insert(DeviceId, {[Status, UpdatedAt, get_acl(Device), Devaddr, ProductId, DeviceSecret], node()}).
|
||||||
|
|
||||||
get_acl(Device) when is_map(Device) ->
|
get_acl(Device) when is_map(Device) ->
|
||||||
ACL = maps:get(<<"ACL">>, Device, #{}),
|
ACL = maps:get(<<"ACL">>, Device, #{}),
|
||||||
@ -163,7 +160,7 @@ sync_parse(OffLine) ->
|
|||||||
{_, DeviceId, V} = X,
|
{_, DeviceId, V} = X,
|
||||||
Now = dgiot_datetime:now_secs(),
|
Now = dgiot_datetime:now_secs(),
|
||||||
case V of
|
case V of
|
||||||
{[_, Last, Acl, DeviceName, Devaddr, ProductId, DeviceSecret], Node} when (Now - Last) < 0 ->
|
{[_, Last, Acl, Devaddr, ProductId, DeviceSecret], Node} when (Now - Last) < 0 ->
|
||||||
case dgiot_parse:update_object(<<"Device">>, DeviceId, #{<<"status">> => <<"ONLINE">>}) of
|
case dgiot_parse:update_object(<<"Device">>, DeviceId, #{<<"status">> => <<"ONLINE">>}) of
|
||||||
{ok, _R} ->
|
{ok, _R} ->
|
||||||
Productname =
|
Productname =
|
||||||
@ -173,13 +170,13 @@ sync_parse(OffLine) ->
|
|||||||
_ ->
|
_ ->
|
||||||
<<"">>
|
<<"">>
|
||||||
end,
|
end,
|
||||||
?MLOG(info, #{<<"deviceid">> => DeviceId, <<"devaddr">> => Devaddr, <<"productid">> => ProductId, <<"productname">> => Productname, <<"devicename">> => DeviceName, <<"status">> => <<"上线"/utf8>>}, ['device_statuslog']),
|
?MLOG(info, #{<<"deviceid">> => DeviceId, <<"devaddr">> => Devaddr, <<"productid">> => ProductId, <<"productname">> => Productname, <<"status">> => <<"上线"/utf8>>}, ['device_statuslog']),
|
||||||
dgiot_mnesia:insert(DeviceId, {[true, Now, Acl, DeviceName, Devaddr, ProductId, DeviceSecret], Node});
|
dgiot_mnesia:insert(DeviceId, {[true, Now, Acl, Devaddr, ProductId, DeviceSecret], Node});
|
||||||
_ ->
|
_ ->
|
||||||
pass
|
pass
|
||||||
end,
|
end,
|
||||||
timer:sleep(50);
|
timer:sleep(50);
|
||||||
{[true, Last, Acl, DeviceName, Devaddr, ProductId, DeviceSecret], Node} when (Now - Last) > OffLine ->
|
{[true, Last, Acl, Devaddr, ProductId, DeviceSecret], Node} when (Now - Last) > OffLine ->
|
||||||
case dgiot_parse:update_object(<<"Device">>, DeviceId, #{<<"status">> => <<"OFFLINE">>}) of
|
case dgiot_parse:update_object(<<"Device">>, DeviceId, #{<<"status">> => <<"OFFLINE">>}) of
|
||||||
{ok, _R} ->
|
{ok, _R} ->
|
||||||
Productname =
|
Productname =
|
||||||
@ -189,14 +186,14 @@ sync_parse(OffLine) ->
|
|||||||
_ ->
|
_ ->
|
||||||
<<"">>
|
<<"">>
|
||||||
end,
|
end,
|
||||||
?MLOG(info, #{<<"deviceid">> => DeviceId, <<"devaddr">> => Devaddr, <<"productid">> => ProductId, <<"productname">> => Productname, <<"devicename">> => DeviceName, <<"status">> => <<"下线"/utf8>>}, ['device_statuslog']),
|
?MLOG(info, #{<<"deviceid">> => DeviceId, <<"devaddr">> => Devaddr, <<"productid">> => ProductId, <<"productname">> => Productname, <<"status">> => <<"下线"/utf8>>}, ['device_statuslog']),
|
||||||
dgiot_umeng:save_devicestatus(DeviceId, <<"OFFLINE">>),
|
dgiot_umeng:save_devicestatus(DeviceId, <<"OFFLINE">>),
|
||||||
dgiot_mnesia:insert(DeviceId, {[false, Last, Acl, DeviceName, Devaddr, ProductId, DeviceSecret], Node});
|
dgiot_mnesia:insert(DeviceId, {[false, Last, Acl, Devaddr, ProductId, DeviceSecret], Node});
|
||||||
_ ->
|
_ ->
|
||||||
pass
|
pass
|
||||||
end,
|
end,
|
||||||
timer:sleep(50);
|
timer:sleep(50);
|
||||||
{[false, Last, Acl, DeviceName, Devaddr, ProductId, DeviceSecret], Node} when (Now - Last) < OffLine ->
|
{[false, Last, Acl, Devaddr, ProductId, DeviceSecret], Node} when (Now - Last) < OffLine ->
|
||||||
case dgiot_parse:update_object(<<"Device">>, DeviceId, #{<<"status">> => <<"ONLINE">>}) of
|
case dgiot_parse:update_object(<<"Device">>, DeviceId, #{<<"status">> => <<"ONLINE">>}) of
|
||||||
{ok, _R} ->
|
{ok, _R} ->
|
||||||
Productname =
|
Productname =
|
||||||
@ -206,8 +203,8 @@ sync_parse(OffLine) ->
|
|||||||
_ ->
|
_ ->
|
||||||
<<"">>
|
<<"">>
|
||||||
end,
|
end,
|
||||||
?MLOG(info, #{<<"deviceid">> => DeviceId, <<"devaddr">> => Devaddr, <<"productid">> => ProductId, <<"productname">> => Productname, <<"devicename">> => DeviceName, <<"status">> => <<"上线"/utf8>>}, ['device_statuslog']),
|
?MLOG(info, #{<<"deviceid">> => DeviceId, <<"devaddr">> => Devaddr, <<"productid">> => ProductId, <<"productname">> => Productname, <<"status">> => <<"上线"/utf8>>}, ['device_statuslog']),
|
||||||
dgiot_mnesia:insert(DeviceId, {[true, Last, Acl, DeviceName, Devaddr, ProductId, DeviceSecret], Node});
|
dgiot_mnesia:insert(DeviceId, {[true, Last, Acl, Devaddr, ProductId, DeviceSecret], Node});
|
||||||
_ ->
|
_ ->
|
||||||
pass
|
pass
|
||||||
end,
|
end,
|
||||||
|
@ -109,7 +109,7 @@ init(?TYPE, ChannelId, Args) ->
|
|||||||
{ok, State, []}.
|
{ok, State, []}.
|
||||||
|
|
||||||
handle_init(State) ->
|
handle_init(State) ->
|
||||||
erlang:send_after(300, self(), {message, <<"_Pool">>, load}),
|
erlang:send_after(500, self(), {message, <<"_Pool">>, load}),
|
||||||
erlang:send_after(3 * 60 * 1000, self(), {message, <<"_Pool">>, check}),
|
erlang:send_after(3 * 60 * 1000, self(), {message, <<"_Pool">>, check}),
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
|
@ -26,3 +26,13 @@
|
|||||||
|
|
||||||
## 室内定位
|
## 室内定位
|
||||||
通室内定位设备定位,需要专用的定位网关和设备,定位精度可以到米级,投资巨大
|
通室内定位设备定位,需要专用的定位网关和设备,定位精度可以到米级,投资巨大
|
||||||
|
|
||||||
|
## 离线地图
|
||||||
|
|
||||||
|
https://github.com/dxxzst/OfflineMap
|
||||||
|
|
||||||
|
### 地图瓦片下载工具及配置
|
||||||
|
|
||||||
|
+ 工具下载地址:https://pan.baidu.com/s/1miMF9nM
|
||||||
|
|
||||||
|
+ 工具开源地址:https://github.com/luxiaoxun/MapDownloader
|
||||||
|
@ -8,22 +8,19 @@
|
|||||||
+ 设备侧topic交互采用 {productId}/{deviceAddr}的组合来唯一标识设备, deviceAddr为设备物理地址
|
+ 设备侧topic交互采用 {productId}/{deviceAddr}的组合来唯一标识设备, deviceAddr为设备物理地址
|
||||||
+ 用户侧topic交互采用{deviceId}来唯一标识设备,用{userId}来唯一标识用户,deviceId为设备虚拟地址
|
+ 用户侧topic交互采用{deviceId}来唯一标识设备,用{userId}来唯一标识用户,deviceId为设备虚拟地址
|
||||||
|
|
||||||
|
|
||||||
### 鉴权设计
|
### 鉴权设计
|
||||||
+ deviceId=md5("Device" + {productId} + {devAddr}).subString(10)
|
+ deviceId=md5("Device" + {productId} + {devAddr}).subString(10)
|
||||||
+ %u 表示用Username做ACL规则
|
+ %u 表示用Username做ACL规则
|
||||||
+ %c 表示用ClientId做ACL规则
|
+ %c 表示用clientId做ACL规则
|
||||||
+ %d 表示用DeviceAddr做ACL规则, Token是dgiot用户登录权限系统的token,与API权限一致
|
- 用户侧clientId用Token做ACL规则, Token是dgiot用户登录权限系统的token,与API权限一致
|
||||||
+ %t 表示用Token做ACL规则, Token是dgiot用户登录权限系统的token,与API权限一致
|
- 设备侧clientId可用deviceAddr或者deviceId,如果用deviceAddr需要用户自己保证唯一性
|
||||||
|
|
||||||
| 客户端 | Username | Password | ClientId | 登录鉴权| 订阅ACL | 发布ACL|
|
| 客户端 | Username | Password | ClientId | 登录鉴权| 订阅ACL | 发布ACL|
|
||||||
| -------- | -------- | ------- | -------- |-------- | ------- | -------- |
|
| -------- | -------- | ------- | -------- |-------- | ------- | -------- |
|
||||||
| Device |{productId}|{productSecret}|{deviceId}| 一型一密 | $dg/device/%u/# | $dg/thing/%u/# |
|
| Device |{productId}|{productSecret}|{clientId}| 一型一密 | $dg/device/%u/# | $dg/thing/%u/# |
|
||||||
| Device |{productId}|{deviceSecret}|{deviceId}| 一机一密 | $dg/device/%u/%d/# | $dg/thing/%u/%d/# |
|
| Device |{productId}|{deviceSecret}|{clientId}| 一机一密 | $dg/device/%u/%d/# | $dg/thing/%u/%c/# |
|
||||||
| Device |{productId}|{productSecret}|{deviceId}| 证书加密 | $dg/device/%u/# | $dg/thing/%u/# |
|
| Device |{productId}|{productSecret}|{clientId}| 证书加密 | $dg/device/%u/# | $dg/thing/%u/# |
|
||||||
| User |{userId}|{Token}|{Token}| Token认证 | $dg/user/%t/# | $dg/thing/%t/# |
|
| User |{userId}|{Token}|{Token}| Token认证 | $dg/user/%c/# | $dg/thing/%c/# |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## topic设计
|
## topic设计
|
||||||
| 分类 | Topic | 发布者 | 订阅者 |
|
| 分类 | Topic | 发布者 | 订阅者 |
|
||||||
|
@ -20,56 +20,88 @@
|
|||||||
|
|
||||||
%% ACL Callbacks
|
%% ACL Callbacks
|
||||||
-export([
|
-export([
|
||||||
check_acl/5
|
check_acl/5
|
||||||
, description/0
|
, description/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
check_acl(ClientInfo = #{ clientid := _Clientid }, PubSub, Topic, _NoMatchAction, _Params) ->
|
check_acl(ClientInfo, PubSub, <<"$dg/", _/binary>> = Topic, _NoMatchAction, _Params) ->
|
||||||
|
io:format("~s ~p Topic: ~p _NoMatchAction ~p ~n", [?FILE, ?LINE, Topic, _NoMatchAction]),
|
||||||
_Username = maps:get(username, ClientInfo, undefined),
|
_Username = maps:get(username, ClientInfo, undefined),
|
||||||
Acls = [],
|
case do_check(ClientInfo, PubSub, Topic) of
|
||||||
case match(ClientInfo, PubSub, Topic, Acls) of
|
|
||||||
allow ->
|
allow ->
|
||||||
ok;
|
{stop, allow};
|
||||||
%% {stop, allow};
|
|
||||||
deny ->
|
deny ->
|
||||||
%% {stop, deny};
|
{stop, deny};
|
||||||
{stop, allow};
|
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
end.
|
end;
|
||||||
|
|
||||||
description() -> "Acl with Mnesia".
|
check_acl(_ClientInfo, _PubSub, _Topic, _NoMatchAction, _Params) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
description() -> "Acl with Dlink".
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
%%-------------------------------------------------------------------
|
%%-------------------------------------------------------------------
|
||||||
|
|
||||||
match(_ClientInfo, _PubSub, _Topic, []) ->
|
%% 用户订阅 "$dg/user/deviceid/#"
|
||||||
nomatch;
|
do_check(#{clientid := ClientID, username := Username} = _ClientInfo, subscribe, <<"$dg/user/", DeviceInfo/binary>> = Topic)
|
||||||
match(ClientInfo, PubSub, Topic, [ {_, ACLTopic, Action, Access, _} | Acls]) ->
|
when ClientID =/= undefined ->
|
||||||
case match_actions(PubSub, Action) andalso match_topic(ClientInfo, Topic, ACLTopic) of
|
io:format("~s ~p Topic: ~p~n", [?FILE, ?LINE, Topic]),
|
||||||
true -> Access;
|
[DeviceID | _] = binary:split(DeviceInfo, <<"/">>),
|
||||||
false -> match(ClientInfo, PubSub, Topic, Acls)
|
%% 此时的ClientID为 Token
|
||||||
|
case check_device_acl(ClientID, DeviceID, Username) of
|
||||||
|
ok ->
|
||||||
|
allow;
|
||||||
|
_ ->
|
||||||
|
deny
|
||||||
|
end;
|
||||||
|
|
||||||
|
%%"$dg/device/productid/devaddr/#"
|
||||||
|
do_check(#{clientid := ClientID} = _ClientInfo, subscribe, <<"$dg/device/", DeviceInfo/binary>> = Topic) ->
|
||||||
|
io:format("~s ~p Topic: ~p~n", [?FILE, ?LINE, Topic]),
|
||||||
|
[ProuctID, Devaddr | _] = binary:split(DeviceInfo, <<"/">>, [global]),
|
||||||
|
DeviceID = dgiot_parse:get_deviceid(ProuctID, Devaddr),
|
||||||
|
case ClientID == DeviceID of
|
||||||
|
true ->
|
||||||
|
allow;
|
||||||
|
_ ->
|
||||||
|
deny
|
||||||
|
end;
|
||||||
|
|
||||||
|
%%"$dg/thing/deviceid/#"
|
||||||
|
%%"$dg/thing/productid/devaddr/#"
|
||||||
|
do_check(#{clientid := ClientID, username := UserId} = _ClientInfo, publish, <<"$dg/thing/", DeviceInfo/binary>> = Topic)
|
||||||
|
when ClientID =/= undefined ->
|
||||||
|
io:format("~s ~p Topic: ~p~n", [?FILE, ?LINE, Topic]),
|
||||||
|
[Id, Devaddr | _] = binary:split(DeviceInfo, <<"/">>, [global]),
|
||||||
|
%% 先判断clientid为Token
|
||||||
|
case check_device_acl(ClientID, Id, UserId) of
|
||||||
|
ok ->
|
||||||
|
allow;
|
||||||
|
_ ->
|
||||||
|
DeviceID = dgiot_parse:get_deviceid(Id, Devaddr),
|
||||||
|
case ClientID == DeviceID of
|
||||||
|
true ->
|
||||||
|
allow;
|
||||||
|
_ ->
|
||||||
|
deny
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
do_check(_ClientInfo, _PubSub, Topic) ->
|
||||||
|
io:format("~s ~p Topic: ~p~n", [?FILE, ?LINE, Topic]),
|
||||||
|
deny.
|
||||||
|
|
||||||
|
check_device_acl(Token, DeviceID, UserId) ->
|
||||||
|
case dgiot_auth:get_session(Token) of
|
||||||
|
#{<<"objectId">> := UserId, <<"ACL">> := Acl} ->
|
||||||
|
case dgiot_device:get_acl(DeviceID) of
|
||||||
|
Acl ->
|
||||||
|
ok;
|
||||||
|
_ ->
|
||||||
|
deny
|
||||||
|
end;
|
||||||
|
_ -> deny
|
||||||
end.
|
end.
|
||||||
|
|
||||||
match_topic(ClientInfo, Topic, ACLTopic) when is_binary(Topic) ->
|
|
||||||
emqx_topic:match(Topic, feed_var(ClientInfo, ACLTopic)).
|
|
||||||
|
|
||||||
match_actions(subscribe, sub) -> true;
|
|
||||||
match_actions(publish, pub) -> true;
|
|
||||||
match_actions(_, _) -> false.
|
|
||||||
|
|
||||||
feed_var(ClientInfo, Pattern) ->
|
|
||||||
feed_var(ClientInfo, emqx_topic:words(Pattern), []).
|
|
||||||
feed_var(_ClientInfo, [], Acc) ->
|
|
||||||
emqx_topic:join(lists:reverse(Acc));
|
|
||||||
feed_var(ClientInfo = #{clientid := undefined}, [<<"%c">>|Words], Acc) ->
|
|
||||||
feed_var(ClientInfo, Words, [<<"%c">>|Acc]);
|
|
||||||
feed_var(ClientInfo = #{clientid := ClientId}, [<<"%c">>|Words], Acc) ->
|
|
||||||
feed_var(ClientInfo, Words, [ClientId |Acc]);
|
|
||||||
feed_var(ClientInfo = #{username := undefined}, [<<"%u">>|Words], Acc) ->
|
|
||||||
feed_var(ClientInfo, Words, [<<"%u">>|Acc]);
|
|
||||||
feed_var(ClientInfo = #{username := Username}, [<<"%u">>|Words], Acc) ->
|
|
||||||
feed_var(ClientInfo, Words, [Username|Acc]);
|
|
||||||
feed_var(ClientInfo, [W|Words], Acc) ->
|
|
||||||
feed_var(ClientInfo, Words, [W|Acc]).
|
|
||||||
|
@ -22,11 +22,13 @@
|
|||||||
%%
|
%%
|
||||||
%% @end
|
%% @end
|
||||||
-module(dgiot_mqtt_app).
|
-module(dgiot_mqtt_app).
|
||||||
-emqx_plugin(?MODULE).
|
-emqx_plugin(auth).
|
||||||
-behaviour(application).
|
-behaviour(application).
|
||||||
|
|
||||||
%% Application callbacks
|
%% Application callbacks
|
||||||
-export([start/2, stop/1]).
|
-export([start/2,
|
||||||
|
prep_stop/1,
|
||||||
|
stop/1]).
|
||||||
|
|
||||||
|
|
||||||
%% ===================================================================
|
%% ===================================================================
|
||||||
@ -35,8 +37,21 @@
|
|||||||
|
|
||||||
start(_StartType, _StartArgs) ->
|
start(_StartType, _StartArgs) ->
|
||||||
{ok, Sup} = dgiot_mqtt_sup:start_link(),
|
{ok, Sup} = dgiot_mqtt_sup:start_link(),
|
||||||
|
_ = load_auth_hook(),
|
||||||
|
_ = load_acl_hook(),
|
||||||
{ok, Sup}.
|
{ok, Sup}.
|
||||||
|
|
||||||
|
|
||||||
stop(_State) ->
|
stop(_State) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
prep_stop(State) ->
|
||||||
|
emqx:unhook('client.authenticate', fun dgiot_mqtt_auth:check/3),
|
||||||
|
emqx:unhook('client.check_acl', fun dgiot_mqtt_acl:check_acl/5),
|
||||||
|
State.
|
||||||
|
|
||||||
|
load_auth_hook() ->
|
||||||
|
emqx:hook('client.authenticate', fun dgiot_mqtt_auth:check/3, [#{hash_type => plain}]).
|
||||||
|
|
||||||
|
load_acl_hook() ->
|
||||||
|
emqx:hook('client.check_acl', fun dgiot_mqtt_acl:check_acl/5, [#{}]).
|
||||||
|
@ -31,50 +31,47 @@
|
|||||||
, description/0
|
, description/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
check(#{username := Username}, AuthResult, _)
|
||||||
|
when Username == <<"anonymous">> orelse Username == undefined orelse Username == <<>> ->
|
||||||
|
io:format("~s ~p Username: ~p~n", [?FILE, ?LINE, Username]),
|
||||||
|
{stop, AuthResult#{anonymous => true, auth_result => success}};
|
||||||
|
|
||||||
check(ClientInfo = #{clientid := _Clientid,
|
%% 当 clientid 和 password 为token 且相等的时候为用户登录
|
||||||
password := NPassword}, AuthResult, #{hash_type := HashType}) ->
|
check(#{clientid := Token, username := UserId, password := Token}, AuthResult, #{hash_type := _HashType}) ->
|
||||||
_Username = maps:get(username, ClientInfo, undefined),
|
io:format("~s ~p UserId: ~p~n", [?FILE, ?LINE, UserId]),
|
||||||
List = [],
|
case dgiot_auth:get_session(Token) of
|
||||||
case match_password(NPassword, HashType, List) of
|
#{<<"objectId">> := UserId} ->
|
||||||
false ->
|
{stop, AuthResult#{anonymous => false, auth_result => success}};
|
||||||
%% ?LOG(error, "[Mnesia] Auth from mnesia failed: ~p", [ClientInfo]),
|
|
||||||
{stop, AuthResult#{anonymous => false, auth_result => password_error}};
|
|
||||||
_ ->
|
_ ->
|
||||||
{stop, AuthResult#{anonymous => false, auth_result => success}}
|
{stop, AuthResult#{anonymous => false, auth_result => password_error}}
|
||||||
end.
|
end;
|
||||||
|
|
||||||
|
%% ClientID 为deviceID 或者 deviceAddr Username 为 ProductID
|
||||||
|
%% 1、 尝试1型1密认证
|
||||||
|
%% 2、 尝试ClientID 为deviceID的1机1密认证
|
||||||
|
%% 3、 尝试ClientID 为deviceAddr的1机1密认证
|
||||||
|
check(#{clientid := ClientId, username := ProductID, password := Password}, AuthResult, #{hash_type := _HashType}) ->
|
||||||
|
io:format("~s ~p ProductID: ~p ClientId ~p Password ~p ~n", [?FILE, ?LINE, ProductID, ClientId, Password]),
|
||||||
|
case dgiot_product:lookup_prod(ProductID) of
|
||||||
|
{ok, #{<<"productSecret">> := Password}} ->
|
||||||
|
{stop, AuthResult#{anonymous => false, auth_result => success}};
|
||||||
|
_ ->
|
||||||
|
case dgiot_device:lookup(ClientId) of
|
||||||
|
{ok, #{<<"devicesecret">> := Password}} ->
|
||||||
|
{stop, AuthResult#{anonymous => false, auth_result => success}};
|
||||||
|
_ ->
|
||||||
|
DeviceID = dgiot_parse:get_deviceid(ProductID, ClientId),
|
||||||
|
case dgiot_device:lookup(DeviceID) of
|
||||||
|
{ok, #{<<"devicesecret">> := Password, <<"devaddr">> := ClientId}} ->
|
||||||
|
{stop, AuthResult#{anonymous => false, auth_result => success}};
|
||||||
|
_ ->
|
||||||
|
{stop, AuthResult#{anonymous => false, auth_result => password_error}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
check(#{username := Username}, AuthResult, _) ->
|
||||||
|
io:format("~s ~p Username: ~p~n", [?FILE, ?LINE, Username]),
|
||||||
|
{stop, AuthResult#{anonymous => false, auth_result => password_error}}.
|
||||||
|
|
||||||
description() -> "Authentication with Mnesia".
|
description() -> "Authentication with Mnesia".
|
||||||
|
|
||||||
|
|
||||||
match_password(Password, HashType, HashList) ->
|
|
||||||
lists:any(
|
|
||||||
fun(Secret) ->
|
|
||||||
case is_salt_hash(Secret, HashType) of
|
|
||||||
true ->
|
|
||||||
<<Salt:4/binary, Hash/binary>> = Secret,
|
|
||||||
Hash =:= hash(Password, Salt, HashType);
|
|
||||||
_ ->
|
|
||||||
Secret =:= hash(Password, HashType)
|
|
||||||
end
|
|
||||||
end, HashList).
|
|
||||||
|
|
||||||
hash(undefined, HashType) ->
|
|
||||||
hash(<<>>, HashType);
|
|
||||||
hash(Password, HashType) ->
|
|
||||||
emqx_passwd:hash(HashType, Password).
|
|
||||||
|
|
||||||
hash(undefined, SaltBin, HashType) ->
|
|
||||||
hash(<<>>, SaltBin, HashType);
|
|
||||||
hash(Password, SaltBin, HashType) ->
|
|
||||||
emqx_passwd:hash(HashType, <<SaltBin/binary, Password/binary>>).
|
|
||||||
|
|
||||||
is_salt_hash(_, plain) ->
|
|
||||||
true;
|
|
||||||
is_salt_hash(Secret, HashType) ->
|
|
||||||
not (byte_size(Secret) == len(HashType)).
|
|
||||||
|
|
||||||
len(md5) -> 32;
|
|
||||||
len(sha) -> 40;
|
|
||||||
len(sha256) -> 64;
|
|
||||||
len(sha512) -> 128.
|
|
||||||
|
@ -76,8 +76,6 @@ start(ChannelId, ChannelArgs) ->
|
|||||||
init(?TYPE, ChannelId, #{
|
init(?TYPE, ChannelId, #{
|
||||||
<<"product">> := Products,
|
<<"product">> := Products,
|
||||||
<<"auth">> := Auth}) ->
|
<<"auth">> := Auth}) ->
|
||||||
%% load_auth_hook(),
|
|
||||||
%% load_acl_hook(),
|
|
||||||
%% io:format("Products = ~p.~n", [Products]),
|
%% io:format("Products = ~p.~n", [Products]),
|
||||||
lists:map(fun(X) ->
|
lists:map(fun(X) ->
|
||||||
case X of
|
case X of
|
||||||
@ -104,7 +102,6 @@ init(?TYPE, ChannelId, #{
|
|||||||
},
|
},
|
||||||
dgiot_rule_handler:sysc_rules(),
|
dgiot_rule_handler:sysc_rules(),
|
||||||
emqx_rule_engine_api:list_rules(#{}, []),
|
emqx_rule_engine_api:list_rules(#{}, []),
|
||||||
%% dgiot_matlab_tcp:start(Port, State)
|
|
||||||
{ok, State};
|
{ok, State};
|
||||||
|
|
||||||
init(?TYPE, _ChannelId, _Args) ->
|
init(?TYPE, _ChannelId, _Args) ->
|
||||||
@ -273,10 +270,3 @@ create_rules(RuleID, ChannelId, Description, Rawsql, Target_topic) ->
|
|||||||
_ -> pass
|
_ -> pass
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
%%load_auth_hook() ->
|
|
||||||
%% emqx:hook('client.authenticate', fun dgiot_mqtt_auth:check/3, [#{hash_type => plain}]).
|
|
||||||
%%
|
|
||||||
%%load_acl_hook() ->
|
|
||||||
%% emqx:hook('client.check_acl', fun dgiot_mqtt_acl:check_acl/5, [#{}]).
|
|
||||||
|
@ -8,10 +8,10 @@ parse.delete_field = ACL,objectId,updatedAt,createdAt
|
|||||||
##--------------------------------------------------------------------
|
##--------------------------------------------------------------------
|
||||||
parse.parse_server = http://prod.iotn2n.com:1337
|
parse.parse_server = http://prod.iotn2n.com:1337
|
||||||
parse.parse_path = /parse/
|
parse.parse_path = /parse/
|
||||||
parse.parse_appid = 4def2774e6404456e17f8f58295f5f09
|
parse.parse_appid = d3300b6f53d7ee7da766142f2f7050eb
|
||||||
parse.parse_master_key = 4d5d2aa27bc82eca4797a0ab73e85f43
|
parse.parse_master_key = 3d9707db9414c4e398c5036ddb1b2b62
|
||||||
parse.parse_js_key = 13d64975825ea872ea2f724887861edd
|
parse.parse_js_key = fc8f19e9dcc4b8b7848aed1f8dcda317
|
||||||
parse.parse_rest_key = a216e04802ca54f6e709e7fba1b2965b
|
parse.parse_rest_key = 7957b8a5923c8be145b317521b922b18
|
||||||
|
|
||||||
##--------------------------------------------------------------------
|
##--------------------------------------------------------------------
|
||||||
## parse cache
|
## parse cache
|
||||||
|
BIN
changelog-from-release
Normal file
BIN
changelog-from-release
Normal file
Binary file not shown.
@ -1,9 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# This file is used to install dgiot on linux systems. The operating system
|
# This file is used to install dgiot on linux systems. The operating system
|
||||||
# is required to use systemd to manage services at boot
|
# is required to use systemd to manage services at boot
|
||||||
|
|
||||||
export PATH=$PATH:/usr/local/bin
|
export PATH=$PATH:/usr/local/bin
|
||||||
|
|
||||||
lanip=""
|
lanip=""
|
||||||
wlanip=""
|
wlanip=""
|
||||||
serverFqdn=""
|
serverFqdn=""
|
||||||
|
22
logfile
Normal file
22
logfile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
2022-01-18 13:53:46.308 HKT [155528] 日志: listening on IPv6 address "::1", port 5432
|
||||||
|
2022-01-18 13:53:46.308 HKT [155528] 日志: listening on IPv4 address "127.0.0.1", port 5432
|
||||||
|
2022-01-18 13:53:46.521 HKT [155604] 日志: 数据库上次关闭时间为 2022-01-18 13:53:43 HKT
|
||||||
|
2022-01-18 13:53:46.837 HKT [155528] 日志: 数据库系统准备接受连接
|
||||||
|
2022-01-18 13:59:39.067 HKT [155560] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 13:59:39.103 HKT [152052] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 13:59:57.737 HKT [151300] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:06:45.947 HKT [151988] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:06:45.973 HKT [146740] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:07:01.365 HKT [155248] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:10:00.274 HKT [132012] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:10:00.305 HKT [156660] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:10:16.933 HKT [104700] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:40:29.469 HKT [159448] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:40:29.520 HKT [153628] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:40:34.014 HKT [157792] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:40:46.823 HKT [157024] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:40:46.885 HKT [156156] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:40:49.583 HKT [151236] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:55:02.274 HKT [158952] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:55:02.327 HKT [150864] 致命错误: 角色 "postgres" 不存在
|
||||||
|
2022-01-18 14:55:11.170 HKT [153544] 致命错误: 角色 "postgres" 不存在
|
Loading…
Reference in New Issue
Block a user