首页 文章

使用Grails Spring Security自动登录

提问于
浏览
14

我的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

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

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

  • 1

    也许这个代码来自我写的webapp的snippit会有所帮助 . 我们必须使用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)
          }
    
  • 18

    reauthenticate()方法有两个限制:

    • 它没有检查密码

    • 它没有't fire events. That'为什么许多监听事件的插件可能无法正常工作 . 例如蛮力防御者插件 .

相关问题