48

新しい grails プロジェクトに登録機能を追加しました。テストのために、メールアドレスとパスワードを入力して登録しました。データベースに保存する前に、パスワードをハッシュするために bcrypt アルゴリズムを使用しています。

ただし、登録時に指定したのと同じメールアドレスとパスワードでログインしようとすると、ログインに失敗します。私はアプリケーションをデバッグし、データベースから既にハッシュされたものと比較しようとすると、同じパスワードに対して生成されたハッシュが異なることがわかりました。 .groovy は null を返します)。

これが私のドメインクラスRegistration.groovyです:

class Registration {

   transient springSecurityService

   String fullName
   String password
   String email

   static constraints = {
      fullName(blank:false)
      password(blank:false, password:true)
      email(blank:false, email:true, unique:true)
   }

   def beforeInsert = {
      encodePassword()
   }

   protected void encodePassword() {
      password = springSecurityService.encodePassword(password)
   }
}

ここに私の LoginController.groovy があります:

class LoginController {

   /**
    * Dependency injection for the springSecurityService.
    */
   def springSecurityService

   def index = {
      if (springSecurityService.isLoggedIn()) {
         render(view: "../homepage")
      }
      else {
         render(view: "../index")
      }
   }

   /**
    * Show the login page.
    */
   def handleLogin = {

      if (springSecurityService.isLoggedIn()) {
         render(view: "../homepage")
         return
      }

      def hashPassd = springSecurityService.encodePassword(params.password)
      // Find the username
      def user = Registration.findByEmailAndPassword(params.email,hashPassd)
      if (!user) {
         flash.message = "User not found for email: ${params.email}"
         render(view: "../index")
         return
      } else {
         session.user = user
         render(view: "../homepage")
      }
   }
}

これは私の Config.groovy からのスニペットで、bcrypt アルゴリズムを使用してパスワードとキーイングのラウンド数をハッシュするように grails に指示しています。

grails.plugins.springsecurity.password.algorithm = 'bcrypt'
grails.plugins.springsecurity.password.bcrypt.logrounds = 16
4

2 に答える 2

43

Jan は正しいです。設計上、bcrypt は入力文字列ごとに同じハッシュを生成しません。ただし、ハッシュ化されたパスワードが有効であることを確認する方法があり、それが関連するパスワード エンコーダーに組み込まれています。passwordEncoderそのため、コントローラー ( ) に Beanの依存性注入を追加しdef passwordEncoder、ルックアップを次のように変更します。

def handleLogin = {

   if (springSecurityService.isLoggedIn()) {
      render(view: "../homepage")
      return
   }

   def user = Registration.findByEmail(params.email)
   if (user && !passwordEncoder.isPasswordValid(user.password, params.password, null)) {
      user = null
   }

   if (!user) {
      flash.message = "User not found for email: ${params.email}"
      render(view: "../index")
      return
   }

   session.user = user
   render(view: "../homepage")
}

呼び出しのパスワードをエンコードしないことに注意してくださいisPasswordValid。送信された平文のパスワードを渡します。

また、まったく関係ありませんが、ユーザーをセッションに保存するのは悪い考えです。auth プリンシパルはすぐに利用でき、必要に応じてユーザーを簡単にリロードできるようにユーザー ID をUser.get(springSecurityService.principal.id)保存します (たとえば、切断された潜在的に大きな Hibernate オブジェクトを保存することは、サーバーの唯一のユーザーである場合に開発モードでうまく機能しますが、メモリを大幅に浪費し、切断されているオブジェクトを回避する必要があります (例: を使用する必要mergeがあるなど)。

于 2011-12-12T01:18:06.367 に答える
28

BCrypt ハッシュにはソルトが含まれているため、このアルゴリズムは同じ入力に対して異なるハッシュを返します。Ruby でデモンストレーションさせてください。

> require 'bcrypt'
> p = BCrypt::Password.create "foobar"
=> "$2a$10$DopJPvHidYqWVKq.Sdcy5eTF82MvG1btPO.81NUtb/4XjiZa7ctQS"
> r = BCrypt::Password.create "foobar"
=> "$2a$10$FTHN0Dechb/IiQuyeEwxaOCSdBss1KcC5fBKDKsj85adOYTLOPQf6"
> p == "foobar"
=> true
> r == "foobar"
=> true

したがって、あなたの例に示されている方法でユーザーを見つけるために BCrypt を使用することはできません。代わりに、ユーザーの名前や電子メール アドレスなど、代替の明確なフィールドを使用する必要があります。

于 2011-12-11T22:05:13.367 に答える