在 Grails 服务中注入 LdapTemplate 以返回用户详细信息会导致空指针异常
Posted
技术标签:
【中文标题】在 Grails 服务中注入 LdapTemplate 以返回用户详细信息会导致空指针异常【英文标题】:Injecting LdapTemplate to return user details inside a Grails service causes Null Pointer Exception 【发布时间】:2012-02-26 20:29:34 【问题描述】:我已经在 Spring Security LDAP 上苦苦挣扎了一段时间,就在我终于认为我已经打败了它的时候,它又把我绊倒了。
场景:我让用户使用他们的组织凭据登录,然后我检查内部用户数据库。如果它们不存在,我会在本地创建它们,然后设置它们的本地权限(我无法触摸 LDAP 服务器,只能对其进行身份验证 - 所以我无法在此处添加权限)。这很好用......但我想从 LDAP 添加几个字段 - 他们的全名和电子邮件地址,这就是它出错的地方。
我有 LDAP 搜索在控制器中工作 - 使用以下代码(我已进一步注入 ldapTemplate):
def fullName = ldapTemplate.search("", "(uid=" + uid + "*)", new AttributesMapper()
@Override
public Object mapFromAttributes(Attributes attrs) throws NamingException
return attrs.get("cn").get()
)
这很完美。但是,当我在称为身份验证后的服务中复制此代码时,ldapTemplate 始终为空......我尝试了一些不同的东西,但我无法让它正确填充......任何人都可以阐明为什么?我希望我从凌晨 4 点 21 分开始就在做一些愚蠢的事情,我应该在大约 6 小时前就已经在床上了......
编辑:这是所要求的服务代码,感谢您查看 Burt - 它目前不是很强大,因为我还没有通过简单地创建一个新的本地用户来工作 - 还有工作要做。
package com.myPackage
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
import org.springframework.ldap.core.AttributesMapper
import org.springframework.security.core.Authentication
import org.springframework.security.core.authority.GrantedAuthorityImpl
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
import org.apache.commons.lang.RandomStringUtils
class PostAuthHandlerService implements AuthenticationSuccessHandler
def springSecurityService
def ldapTemplate
private AuthenticationSuccessHandler target = new SavedRequestAwareAuthenticationSuccessHandler();
private List NO_ROLES = [new GrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE)]
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication auth)
def username = auth.principal.getAt("username")
User.withTransaction status ->
// Check to see if this user exists in the local db
def user = User.findByUsername(username)
if (!user) // User doesn't exist yet, so create and make a user...
def userRole = Role.findByAuthority('ROLE_USER') ?:
new Role(authority: 'ROLE_AM').save(failOnError: true)
user = new User(
username: username,
password: auth.getCredentials() ?: placeholderPassword(),
displayName: getLdapDetails("username", "cn") ?: "",
email: getLdapDetails("username", "mail") ?: "",
enabled: true).save(failOnError: true)
UserRole.create user, userRole
else
println("--- You exist already! Updating details")
user.displayName = getLdapDetails("username", "cn") ?: ""
target.onAuthenticationSuccess(request, response, auth)
def getLdapDetails(username, attr)
return ldapTemplate.search("", "(uid=$username*)", new AttributesMapper()
@Override
public Object mapFromAttributes(Attributes attrs) throws NamingException
return attrs.get(attr).get()
)
def placeholderPassword ()
// This is here because we also allow local logins for some users.
// If the password is not available, then create a big ugly one...
return org.apache.commons.lang.RandomStringUtils.randomAlphanumeric(128)
public void proceed(HttpServletRequest request,
HttpServletResponse response, Authentication auth)
target.onAuthenticationSuccess(request, response, auth)
第二次编辑:我一直在尝试各种不同的事情 - 包括尝试使用 springSecurityService.reauthenticate 来让本地用户在会话期间使用而不是 LDAP 用户 - 而且这个 bean 也是空的......它似乎我根本无法在我的服务中注入任何 bean。
我最终找到了这个帖子:http://burtbeckwith.com/blog/?p=993,它给了我一个解决方法,现在我可以让它工作了......但我仍然想知道为什么它一开始就没有......我有这么多在 Grails 中学习 - 很难知道从哪里开始。
提前干杯
史蒂夫
【问题讨论】:
所以和LDAP没有关系,是依赖注入的问题吗?请发布服务代码。 我认为你是对的,因为它适用于其他地方......现在我想我确实尝试放置原始搜索代码(现在与控制器中的所有代码一起工作正常)很早就加入了一项服务,但它没有用......我从来没有在凌晨 4 点建立过这种联系。连续 20 小时编码显然是个坏主意,除非你真的在这样做 - 那么它似乎很好:) Burt,你的(修辞?)问题让我走上了正轨......你能解释一下(在答案中,所以我可以接受)为什么(或很可能为什么)会出现这个问题?干杯,史蒂夫 我在 resources.groovy postAuthHandlerService (PostAuthHandlerService, ref('ldapTemplate')) 中有以下内容,但我得到以下内容:错误创建名为 'postAuthHandlerService' 的 bean:无法解析对 bean 'ldapTemplate 的引用' 同时设置构造函数参数;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'ldapTemplate' is defined 你能分享你在哪里以及如何用 ldap 源填充 ldapTemplate bean 吗? 在 Grails 3 中是否有与此等效的示例? 【参考方案1】:你是如何注入 authenticationSuccessHandler 的?您应该尝试在 resources.xml 中定义 authenticationSuccessHandler
Grails 1.3.5 and Spring Security Core
【讨论】:
为回复干杯。我正在使用 Grails 2,并且在 resources.groovy 中有这个 bean: authenticationSuccessHandler(com.myPackage.PostAuthHandlerService) 你应该设置 authenticationHandler 的 ldapTemplate 属性.. mauthenticationSuccessHandler(com.myPackage.PostAuthHandlerService) ldapTemplate=ref(ldapTemplate) 我会试试的,让你知道我是怎么上手的……谢谢你的提示。如果可行,我会接受答案... 太棒了……那行得通。你能告诉我这和在 bean 签名中添加“, ref(ldapTemplate)”有什么区别吗? resources.xml 类似于 application-context.xml。因此,如果您通过 resources.xml 加载 bean,则必须手动声明所有依赖项。这意味着 authenticationSuccessHandler(com.myPackage.PostAuthHandlerService) 将在没有任何 ldapTemplate 的情况下实例化身份验证处理程序。以上是关于在 Grails 服务中注入 LdapTemplate 以返回用户详细信息会导致空指针异常的主要内容,如果未能解决你的问题,请参考以下文章
在 Grails 服务中注入 LdapTemplate 以返回用户详细信息会导致空指针异常
如何在 Grails 2.0 服务中对 i18n 注入 messageSource 的使用进行单元或集成测试
如何使用 Spring resource.groovy 正确注入 Grails 服务