使用Grails Spring Security自动登录

时间:2011-08-18 21:12:50

标签: grails spring-security

我的Grails应用程序正在使用Spring Security插件。我需要以编程方式登录用户,而且我无法访问他们的密码。我尝试了以下,当使用Acegi插件(Spring Security插件的祖先)时,它应该有效:

// automatically login a user and assign them the USER role. 
// In my app, the email address is also the username
GrantedAuthority[] auths = [new GrantedAuthorityImpl('USER')]
SecurityContextHolder.context.authentication 
        = new UsernamePasswordAuthenticationToken(email, 'unknown', auths)

看起来这几乎有效,因为如果我在执行上述操作后调用springSecurityService.principal,我会找回自动登录用户的电子邮件地址。但是,如果我拨打springSecurityService.currentUser,我会收到错误消息。此错误的根本原因是:

SpringSecurityUtils.securityConfig.userLookup.userDomainClassName

返回“Person”,它不是我的用户类的名称。诸如<sec:loggedInUser>之类的各种标签也不起作用,大概是出于同样的原因。

我想知道这个问题是否与我使用pre-existing domain classes for user and role(而不是插件生成的类)的事实有某种关系?如果用户通过在表单中​​输入用户名和密码(而不是以编程方式)登录,则一切似乎都正常。

更新

关注Burt's advice后,我将上面的代码替换为:

springSecurityService.reauthenticate(email)

但我仍然在SpringSecurityService.getCurrentUser()

中的这些行上收到错误
String className = SpringSecurityUtils.securityConfig.userLookup.userDomainClassName
grailsApplication.getClassForName(className).get(principal.id)

因为className设置为“Person”,而不是我的User类的名称。

3 个答案:

答案 0 :(得分:18)

如果用户存在于数据库中,请使用springSecurityService.reauthenticate() - 请参阅Grails 2的this link或Grails 3的this link

此方法旨在在用户更改使其与数据库不同步时更新身份验证,但对于您希望强制对现有用户进行有效身份验证但不知道的情况,此方法也很有用。密码。

答案 1 :(得分:1)

也许这个代码来自我写的webapp会有所帮助。我们必须使用RESTful API授权用户,并且他们提供了用户名和API密钥。此代码中的关键部分是设置权限和经过身份验证的布尔值。

class CustomAppTokenAuthenticationProvider implements AuthenticationProvider {

  def userDetailsService

  Authentication authenticate(Authentication customAuth) {
    def userDetails = userDetailsService.loadUserByUsername(customAuth.principal)
    def user = User.get(userDetails.id)
    if (user?.apiKey.equals(customAuth.credentials)) {
      customAuth.authorities = userDetails.authorities
      customAuth.authenticated = true
      return customAuth
    } else {
      return customAuth
    }
  }

  boolean supports(Class authentication) {
    return CustomAppTokenAuthentication.class.isAssignableFrom(authentication)
  }
}

以下是来自过滤器的代码,用于拦截API调用以处理身份验证

    def userId = request.getHeader("x-user-external-id")
    def apiKey = request.getHeader("x-user-api-key")
    if (userId && apiKey) {
      def user = User.findByExternalId(userId)

      def myAuth = new CustomAppTokenAuthentication(
              name: userId,
              credentials: apiKey,
              principal: user.username,
              authenticated: false
      )

      def auth = authenticationManager.authenticate(myAuth);
      if (auth?.authorities?.size() >= 0) {
        log.info "Successfully Authenticated ${userId} in object ${auth}"
        // Store to SecurityContextHolder
        SecurityContextHolder.getContext().setAuthentication(myAuth);
      } else {
        SecurityContextHolder.getContext().setAuthentication(null)
      }

答案 2 :(得分:1)

reauthenticate()方法有两个限制:

  • 不检查密码
  • 它不会引发事件。这就是为什么许多监听事件的插件可能无法正常工作的原因。例如蛮力防御者插件。