【问题标题】:What's the correct usage of Friend's bcrypt-credential-fn?Friend 的 bcrypt-credential-fn 的正确用法是什么?
【发布时间】:2013-07-02 20:24:09
【问题描述】:

我正在构建一个简单的练习 Web 应用程序,正在与朋友一起登录,并正在尝试从教程示例中的虚拟内存数据库过渡到访问我的 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 使用提供的用户名参数调用下一个函数从/登录。我看到的示例/教程似乎遵循这种模式。

如果我用“bob@bob.bob”之类的用户名呼叫用户,它会返回一个带有朋友凭据的哈希映射

{"bob@bob.bob" {:username "bob@bob.bob", 
              :password "$2a$10$rtDxqCqZRIRFFzjCYD9d.uiQ2NuUMXto.jCbWNPtVKF1y/d4WPL/C",          
              :roles #{:practice.models.db/admin}}}

如果我将用户名硬编码到 users 函数中,它可以正常工作并且我可以使用它登录,但是当用 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

我在这里做错了什么?

【问题讨论】:

    标签: web-applications clojure compojure


    【解决方案1】:

    所以我想通了。

    我的错误是对示例数据的理解有点过于字面意思了。

    bcrypt-credentials-fn 正在从它调用的函数返回的哈希映射中寻找 :username,这意味着我的凭证映射嵌套得太深。这适用于我的示例。

    {:username "bob@bob.bob", 
              :password "$2a$10$rtDxqCqZRIRFFzjCYD9d.uiQ2NuUMXto.jCbWNPtVKF1y/d4WPL/C",          
              :roles #{:practice.models.db/admin}}
    

    它会对其进行硬编码,因为它实际上会查找 ["bob@bob.bob" :username],它是有效的。

    希望这可以帮助其他遇到同样问题的人。

    【讨论】:

    • 我做了同样的错误假设,我通过阅读您的问题和答案解决了我的问题。非常感谢您的提问!
    【解决方案2】:
    (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 中的用户保持原样

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-09
      • 2011-04-15
      • 1970-01-01
      • 2012-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多