关于用户的登录。
user_login_authentication(Username, AuthProps) ->
case http_req(p(user_path), q([{username, Username}|AuthProps])) of
{error, _} = E -> E;
deny -> {refused, "Denied by HTTP plugin", []};
"allow" ++ Rest -> Tags = [list_to_atom(T) ||
T <- string:tokens(Rest, " ")],
{ok, #auth_user{username = Username,
tags = Tags,
impl = none}};
Other -> {error, {bad_response, Other}}
end.
q(Args) ->
string:join([escape(K, V) || {K, V} <- Args], "&").
escape(K, Map) when is_map(Map) ->
string:join([escape(rabbit_data_coercion:to_list(K) ++ "." ++ rabbit_data_coercion:to_list(Key), Value)
|| {Key, Value} <- maps:to_list(Map)], "&");
escape(K, V) ->
rabbit_data_coercion:to_list(K) ++ "=" ++ rabbit_http_util:quote_plus(V).
首先,所有的参数都会通过q()方法强行被组装成url中get方法参数链接的形式,类似username=username&password=password的字符串,便于在后面的请求中便于装配。
之后根据p()得到配置中的rabbitmq_auth_backend_http参数,也就是目标验证服务的地址。
p(PathName) ->
{ok, Path} = application:get_env(rabbitmq_auth_backend_http, PathName),
Path.
在得到了以上参数之后,也就是服务目标地址与验证所需要的参数,通过http_req方法调用,准备开始发送http请求。
http_req(Path, Query) -> http_req(Path, Query, ?RETRY_ON_KEEPALIVE_CLOSED).
http_req(Path, Query, Retry) ->
case do_http_req(Path, Query) of
{error, socket_closed_remotely} ->
%% HTTP keepalive connection can no longer be used. Retry the request.
case Retry > 0 of
true -> http_req(Path, Query, Retry - 1);
false -> {error, socket_closed_remotely}
end;
Other -> Other
end.
do_http_req(PathName, Query) ->
URI = uri_parser:parse(PathName, [{port, 80}]),
{host, Host} = lists:keyfind(host, 1, URI),
{port, Port} = lists:keyfind(port, 1, URI),
HostHdr = rabbit_misc:format("~s:~b", [Host, Port]),
{ok, Method} = application:get_env(rabbitmq_auth_backend_http, http_method),
Request = case rabbit_data_coercion:to_atom(Method) of
get -> {PathName ++ "?" ++ Query,
[{"Host", HostHdr}]};
post -> {PathName,
[{"Host", HostHdr}],
"application/x-www-form-urlencoded",
Query}
end,
HttpOpts = case application:get_env(rabbitmq_auth_backend_http,
ssl_options) of
{ok, Opts} when is_list(Opts) -> [{ssl, Opts}];
_ -> []
end,
case httpc:request(Method, Request, HttpOpts, []) of
{ok, {{_HTTP, Code, _}, _Headers, Body}} ->
case Code of
200 -> case parse_resp(Body) of
{error, _} = E -> E;
Resp -> Resp
end;
_ -> {error, {Code, Body}}
end;
{error, _} = E ->
E
end.
在do_http_req()方法,首先根据之前得到的目标验证服务地址解析相应的 主机名和端口号(默认端口号80)。在从rabbitmq的配置文件中读取rabbitmq_auth_backend_http里的http_method参数,以此来确定验证所需要的方法(只支持get或者post方法),并再次读取配置中ssl_opts作为访问时需要的证书,。
之后组装为request直接发送请求至相应的认证服务。
如果连接失败,也会在相应的重试次数下继续尝试连接。
在获得response之后并确认成功之后,对于用户登录的认证之外,还可以接收除了allow之后,可以在之后空格之后加角色,会解析成tags一并返回,而除了allow之外的所有请求都会被视为拒绝。
以上是用户的登录的验证。
其他的关于资源的权限授权也与以上大同小异。