在 Apache Shiro Grails 中使用 passwordHash 登录
Login with passwordHash in Apache Shiro Grails
我在 grails 中使用 Apache Shiro 插件来处理用户身份验证。
我想在系统的管理部分添加一项功能,我们的管理员可以在其中为特定用户登录。
我想避免为管理员创建一个新的复杂界面。
当我不知道他的密码,但只知道他的密码哈希时,如何以用户身份登录?
这似乎是一个带有大量安全问题的可怕想法。相反,您应该考虑允许已登录的管理员临时以用户身份登录。
这些可以帮助您以编程方式以用户身份登录Grails - ShiroSecurity - manually login user and Grails: ShiroSecurity - log in user without UsernamePasswordToken
我最终解决了它,但我不确定我的解决方案的安全性,所以我希望你对它发表评论。
我在管理控制器中创建了新的操作登录。此控制器只能由管理员访问,其他任何人都无法访问。动作看起来像:
def signIn(String username) {
def authToken = new UsernamePasswordToken(username, params.password as String)
// Specific setting for administrator signIn
//
params.rememberMe = false
params.targetUri = '/'
authToken.host = 'admin'
// If a controller redirected to this page, redirect back
// to it. Otherwise redirect to the root URI.
def targetUri = params.targetUri ?: "/index/index"
// Handle requests saved by Shiro filters.
SavedRequest savedRequest = WebUtils.getSavedRequest(request)
if (savedRequest) {
targetUri = savedRequest.requestURI - request.contextPath
if (savedRequest.queryString) targetUri = targetUri + '?' + savedRequest.queryString
}
try{
// Perform the actual login. An AuthenticationException
// will be thrown if the username is unrecognised or the
// password is incorrect.
SecurityUtils.subject
SecurityUtils.subject.login(authToken)
log.info "Redirecting to ${targetUri}."
redirect(uri: targetUri)
}
catch (AuthenticationException ex){
// Authentication failed, so display the appropriate message
// on the login page.
log.info "Authentication failure for user ${params.username}."
flash.message = message(code: "login.failed")
// Keep the username and "remember me" setting so that the
// user doesn't have to enter them again.
def m = [ username: params.username ]
// Remember the target URI too.
if (params.targetUri) {
m["targetUri"] = params.targetUri
}
// Now redirect back to the login page.
redirect(action: "login", params: m)
}
}
而且我还稍微修改了我的 DbShiroRealm。
def authenticate(authToken) {
log.info "Attempting to authenticate ${authToken.username} in DB realm..."
def username = authToken.username
// Null username is invalid
if (username == null) {
throw new AccountException("Null usernames are not allowed by this realm.")
}
// Get the user with the given username. If the user is not
// found, then they don't have an account and we throw an
// exception.
def user = User.findByUsername(username)
if (!user) {
throw new UnknownAccountException("No account found for user [${username}]")
}
log.info "Found user ${user.username} in DB"
// Now check the user's password against the hashed value stored
// in the database.
def account = new SimpleAccount(username, user.password, "ShiroDbRealm")
if( !(authToken.host == 'admin')) { // skips password authentication
if (!credentialMatcher.doCredentialsMatch(authToken, account)) {
log.info "Invalid password (DB realm)"
throw new IncorrectCredentialsException("Invalid password for user ${username}")
}
}
return account
}
我使用了 UsernamePasswordToken 中的主机字段来携带正在登录的信息。
覆盖 UsernamePasswordToken 并添加额外的布尔字段以跳过密码验证会更合适。
我在 grails 中使用 Apache Shiro 插件来处理用户身份验证。
我想在系统的管理部分添加一项功能,我们的管理员可以在其中为特定用户登录。
我想避免为管理员创建一个新的复杂界面。
当我不知道他的密码,但只知道他的密码哈希时,如何以用户身份登录?
这似乎是一个带有大量安全问题的可怕想法。相反,您应该考虑允许已登录的管理员临时以用户身份登录。
这些可以帮助您以编程方式以用户身份登录Grails - ShiroSecurity - manually login user and Grails: ShiroSecurity - log in user without UsernamePasswordToken
我最终解决了它,但我不确定我的解决方案的安全性,所以我希望你对它发表评论。
我在管理控制器中创建了新的操作登录。此控制器只能由管理员访问,其他任何人都无法访问。动作看起来像:
def signIn(String username) {
def authToken = new UsernamePasswordToken(username, params.password as String)
// Specific setting for administrator signIn
//
params.rememberMe = false
params.targetUri = '/'
authToken.host = 'admin'
// If a controller redirected to this page, redirect back
// to it. Otherwise redirect to the root URI.
def targetUri = params.targetUri ?: "/index/index"
// Handle requests saved by Shiro filters.
SavedRequest savedRequest = WebUtils.getSavedRequest(request)
if (savedRequest) {
targetUri = savedRequest.requestURI - request.contextPath
if (savedRequest.queryString) targetUri = targetUri + '?' + savedRequest.queryString
}
try{
// Perform the actual login. An AuthenticationException
// will be thrown if the username is unrecognised or the
// password is incorrect.
SecurityUtils.subject
SecurityUtils.subject.login(authToken)
log.info "Redirecting to ${targetUri}."
redirect(uri: targetUri)
}
catch (AuthenticationException ex){
// Authentication failed, so display the appropriate message
// on the login page.
log.info "Authentication failure for user ${params.username}."
flash.message = message(code: "login.failed")
// Keep the username and "remember me" setting so that the
// user doesn't have to enter them again.
def m = [ username: params.username ]
// Remember the target URI too.
if (params.targetUri) {
m["targetUri"] = params.targetUri
}
// Now redirect back to the login page.
redirect(action: "login", params: m)
}
}
而且我还稍微修改了我的 DbShiroRealm。
def authenticate(authToken) {
log.info "Attempting to authenticate ${authToken.username} in DB realm..."
def username = authToken.username
// Null username is invalid
if (username == null) {
throw new AccountException("Null usernames are not allowed by this realm.")
}
// Get the user with the given username. If the user is not
// found, then they don't have an account and we throw an
// exception.
def user = User.findByUsername(username)
if (!user) {
throw new UnknownAccountException("No account found for user [${username}]")
}
log.info "Found user ${user.username} in DB"
// Now check the user's password against the hashed value stored
// in the database.
def account = new SimpleAccount(username, user.password, "ShiroDbRealm")
if( !(authToken.host == 'admin')) { // skips password authentication
if (!credentialMatcher.doCredentialsMatch(authToken, account)) {
log.info "Invalid password (DB realm)"
throw new IncorrectCredentialsException("Invalid password for user ${username}")
}
}
return account
}
我使用了 UsernamePasswordToken 中的主机字段来携带正在登录的信息。
覆盖 UsernamePasswordToken 并添加额外的布尔字段以跳过密码验证会更合适。