我正在构建一个简单的练习web-app,与朋友一起登录,并尝试从教程示例虚拟内存数据库转换到访问我的DynamoDB数据库。
(handler/site
(friend/authenticate app{
:login-uri "/login"
:unauthorized-redirect-uri "/login"
:credential-fn (partial creds/bcrypt-credential-fn users)
:workflows [(workflows/interactive-form)]})))
(defn users
[uname]
(read-string (get-in (db/valid-user? uname "UB") [:item :friend-map])))
问题出现在我的用户功能,我的理解(这很可能是我错了)阅读朋友源代码是bcrypt-credentials-fn使用提供的用户名参数调用下一个函数来自/ login。我见过的示例/教程似乎遵循这种模式。
如果我使用类似“bob@bob.bob”的用户名呼叫用户,则会返回带有好友凭据的哈希映射
{"bob@bob.bob" {:username "bob@bob.bob",
:password "$2a$10$rtDxqCqZRIRFFzjCYD9d.uiQ2NuUMXto.jCbWNPtVKF1y/d4WPL/C",
:roles #{:practice.models.db/admin}}}
如果我将用户名硬编码到用户函数中,它可以正常工作,我可以用它登录,但是当用uname替换它时,或者(str uname),只是为了确保它是一个字符串。我得到一个空指针异常
java.lang.NullPointerException
BCrypt.java:663 org.mindrot.jbcrypt.BCrypt.hashpw
BCrypt.java:763 org.mindrot.jbcrypt.BCrypt.checkpw
credentials.clj:18 cemerick.friend.credentials/bcrypt-verify
credentials.clj:47 cemerick.friend.credentials/bcrypt-credential-fn
AFn.java:163 clojure.lang.AFn.applyToHelper
AFn.java:151 clojure.lang.AFn.applyTo
core.clj:619 clojure.core/apply
core.clj:2396 clojure.core/partial[fn]
RestFn.java:408 clojure.lang.RestFn.invoke
workflows.clj:80 cemerick.friend.workflows/interactive-form[fn]
friend.clj:180 cemerick.friend/authenticate*[fn]
core.clj:2485 clojure.core/map[fn]
LazySeq.java:42 clojure.lang.LazySeq.sval
LazySeq.java:60 clojure.lang.LazySeq.seq
RT.java:484 clojure.lang.RT.seq
core.clj:133 clojure.core/seq
core.clj:2523 clojure.core/filter[fn]
LazySeq.java:42 clojure.lang.LazySeq.sval
LazySeq.java:60 clojure.lang.LazySeq.seq
LazySeq.java:82 clojure.lang.LazySeq.first
RT.java:577 clojure.lang.RT.first
core.clj:55 clojure.core/first
friend.clj:180 cemerick.friend/authenticate*
friend.clj:208 cemerick.friend/authenticate[fn]
keyword_params.clj:32 ring.middleware.keyword-params/wrap-keyword-params[fn]
nested_params.clj:70 ring.middleware.nested-params/wrap-nested-params[fn]
params.clj:58 ring.middleware.params/wrap-params[fn]
multipart_params.clj:106 ring.middleware.multipart-params/wrap-multipart-params[fn]
flash.clj:31 ring.middleware.flash/wrap-flash[fn]
session.clj:85 ring.middleware.session/wrap-session[fn]
resource.clj:24 ring.middleware.resource/wrap-resource[fn]
file_info.clj:63 ring.middleware.file-info/wrap-file-info[fn]
middleware.clj:12 hiccup.middleware/wrap-base-url[fn]
Var.java:415 clojure.lang.Var.invoke
reload.clj:18 ring.middleware.reload/wrap-reload[fn]
stacktrace.clj:15 ring.middleware.stacktrace/wrap-stacktrace-log[fn]
stacktrace.clj:79 ring.middleware.stacktrace/wrap-stacktrace-web[fn]
jetty.clj:18 ring.adapter.jetty/proxy-handler[fn]
(Unknown Source)
ring.adapter.jetty.proxy$org.eclipse.jetty.server.handler.AbstractHandler$0.handle
HandlerWrapper.java:111 org.eclipse.jetty.server.handler.HandlerWrapper.handle
Server.java:349 org.eclipse.jetty.server.Server.handle
AbstractHttpConnection.java:452 org.eclipse.jetty.server.AbstractHttpConnection.handleRequest
AbstractHttpConnection.java:894 org.eclipse.jetty.server.AbstractHttpConnection.content
AbstractHttpConnection.java:948
org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content
HttpParser.java:857 org.eclipse.jetty.http.HttpParser.parseNext
HttpParser.java:235 org.eclipse.jetty.http.HttpParser.parseAvailable
AsyncHttpConnection.java:76 org.eclipse.jetty.server.AsyncHttpConnection.handle
SelectChannelEndPoint.java:609 org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle
SelectChannelEndPoint.java:45 org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run
QueuedThreadPool.java:599 org.eclipse.jetty.util.thread.QueuedThreadPool.runJob
QueuedThreadPool.java:534 org.eclipse.jetty.util.thread.QueuedThreadPool$3.run
Thread.java:722 java.lang.Thread.run
我在这里做错了什么?
答案 0 :(得分:3)
所以我想通了。
我的错误是将示例数据略微过于字面化。
bcrypt-credntials-fn正在寻找:从它调用的函数返回的hash-map中的用户名,这意味着我的凭据映射嵌套太深了。这适用于我的例子。
{:username "bob@bob.bob",
:password "$2a$10$rtDxqCqZRIRFFzjCYD9d.uiQ2NuUMXto.jCbWNPtVKF1y/d4WPL/C",
:roles #{:practice.models.db/admin}}
它正在努力编写它,因为它本质上寻找[" bob@bob.bob" :username],这是有效的。
希望这有助于其他人遇到同样的问题。
答案 1 :(得分:0)
(def page (handler/site
(friend/authenticate
routes
{:allow-anon? true
:login-uri "/login"
:default-landing-uri "/"
:unauthorized-handler #(-> (h/html5
misc/head
(misc/body [:h3 "You do not have sufficient privileges to access " (:uri %)]
[:a {:class "button secondary" :href "/interactive_form"} "Main"]))
resp/response
(resp/status 401))
;:credential-fn #(creds/bcrypt-credential-fn @users %)
:credential-fn #(creds/bcrypt-credential-fn db/get-user %)
:workflows [(workflows/interactive-form)]})))
...
(ns myapp.models.db
(:require [clojure.java.jdbc :as sql])
(:import java.sql.DriverManager))
(def db {:classname "org.sqlite.JDBC",
:subprotocol "sqlite",
:subname "db.sq1"})
(defn create-user-table []
(sql/with-connection
db
(sql/create-table
:userstable
[:username "varchar(20) PRIMARY KEY"]
[:password "varchar(100)"]
[:email "varchar(100)"]
[:balance "float"]
[:roles "boolean"])))
(defn add-user-record [user]
(if-not (.exists (java.io.File. "./db.sq1"))
(create-user-table))
(sql/with-connection db
(sql/insert-record :userstable user)))
(defn get-user [name]
(sql/with-connection db
(sql/with-query-results
res ["select * from userstable where username = ?" name] (first res))))
... 还允许用户在users.clj中使用