我正在使用Friend在Compojure Web应用程序中构建身份验证。
我为朋友定义了一个定制的身份验证工作流程:
(defn authentication-workflow []
(routes
(GET "/logout" req
(friend/logout* {:status 200}))
(POST "/login" {{:keys [username password]} :params}
(if-let [user-record (authenticate-user username password)]
(workflows/make-auth user-record {:cemerick.friend/workflow :authorisation-workflow})
{:status 401}))))
认证部分被考虑在内:
(defn authenticate-user [username password]
(if-let [user-record (get-user-for-username username)]
(if (creds/bcrypt-verify password (:password user-record))
(dissoc user-record :password))))
这有效,但......
我正在使用AngularJS并且必须发布请求参数导致一些丑陋的Angular代码(在StackOverflow答案的其他地方被抄袭):
$http({
method: 'POST',
url: '/login',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function(obj) {
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data: {
username: username,
password: password
}
});
我宁愿做更简单的调用而只是通过请求体发布一个JSON对象:
$http.post('/login', {username: username, password: password})
我试图在身份验证处理程序中使用“:body”而不是“:params”,但是:body的值似乎既不是JSON也不是Clojure,所以我不知道如何使用它:
{username me@myapp.com, password password}
我已经为我的REST API处理程序正确地运行了JSON请求/响应映射工作流,并且我已经检查过请求标头(例如ContentType)对于JSON是否正确。
这可以通过Compojure / Friend完成,如果是这样的话?
答案 0 :(得分:3)
这是一些工作代码和解释......
首先使用请求正文的朋友工作流程:
(defn authentication-workflow []
(routes
(GET "/logout" req
(friend/logout* {:status 200}))
(POST "/login" {body :body}
(if-let [user-record (authenticate-user body)]
(workflows/make-auth user-record {:cemerick.friend/workflow :authorisation-workflow})
{:status 401}))))
其次,验证功能:
(defn authenticate-user [{username "username" password "password"}]
(if-let [user-record (get-user-for-username username)]
(if (creds/bcrypt-verify password (:password user-record))
(dissoc user-record :password))))
第三,声明了中间件的Compojure应用程序:
(def app
(-> (handler/site
(friend/authenticate app-routes
{:workflows [(authentication-workflow)]}))
(params/wrap-keyword-params)
(json/wrap-json-body)
(json/wrap-json-response {:pretty true})))
最后一个AngularJS代码片段发布凭证(用户名和密码来自AngularJS模型):
$http.post('/login', {username: username, password: password});
所以会发生什么......
Angular javascript代码将JSON发布到Web应用程序登录URL。 “Content-Type”标头自动设置为“application / json”,请求主体自动编码为JSON,例如:
{"username":"batman@batcave.org","password":"tumblerrocks"}
在服务器上,中间件将JSON解析为Clojure映射,并通过“:body”关键字将其呈现给处理程序:
{username batman@batcave.org, password tumblerrocks}
然后,请求将路由到自定义Google朋友身份验证工作流程。
最后,提交的值从Clojure映射中提取并用于验证用户。
答案 1 :(得分:1)
我怀疑你的包装器以错误的顺序应用。检查朋友包装之前(之外)是否应用了ring.middleware.json/wrap-json-body
。
e.g。
(def my-handler (wrap-json-body (cemerick.friend/authenticate ...)))
否则,快速修复可能只是将整个应用程序包装在ring.middleware.json/wrap-json-params