我刚刚为我的新grails项目添加了注册功能.为了测试它,我通过发送电子邮件和密码进行了注册.我使用bcrypt算法对密码进行哈希处理,然后将其保存到数据库中.
但是,当我尝试使用注册时提供的相同电子邮件和密码登录时,登录失败.我调试了应用程序,发现当我尝试与数据库中已经散列的哈希值进行比较时,为同一密码生成的哈希是不同的,因此登录失败(LoginController中的Registration.findByEmailAndPassword(params.email,hashPassd)) .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)
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的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")
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的Config.groovy的片段告诉grails使用bcrypt算法来哈希密码和键控轮数:
grails.plugins.springsecurity.password.algorithm = 'bcrypt'
grails.plugins.springsecurity.password.bcrypt.logrounds = 16
Run Code Online (Sandbox Code Playgroud)
Bur*_*ith 38
Jan是正确的 - 设计的bcrypt不会为每个输入字符串生成相同的哈希.但有一种方法可以检查散列密码是否有效,并将其合并到相关的密码编码器中.因此passwordEncoder
,在控制器(def passwordEncoder
)中为bean 添加依赖注入,并将查找更改为
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")
}
Run Code Online (Sandbox Code Playgroud)
请注意,您不对isPasswordValid
呼叫的密码进行编码- 传递明文提交的密码.
另外 - 完全不相关 - 将用户存储在会话中是个坏主意.auth主体随时可用并存储用户ID,以便根据需要轻松重新加载用户(例如User.get(springSecurityService.principal.id)
,当您是服务器的唯一用户时,存储断开连接的潜在大型Hibernate对象在开发模式下运行良好,但可以是大量浪费内存并迫使您围绕被断开的对象(例如必须使用merge
等).
Jan*_*Jan 20
BCrypt哈希包含salt,因此该算法为同一输入返回不同的哈希值.请允许我在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
Run Code Online (Sandbox Code Playgroud)
因此,BCrypt不能用于以示例中显示的方式查找用户.应该使用替代的明确字段,例如用户名或电子邮件地址.
归档时间: |
|
查看次数: |
20512 次 |
最近记录: |