【问题标题】:Keep users in Config.groovy list in Grails将用户保留在 Grails 中的 Config.groovy 列表中
【发布时间】:2013-07-23 00:54:09
【问题描述】:

有没有办法在 Config.groovy 的列表中定义可以使用我的应用程序的用户?这将使用 Grails 2.2.3 和最新版本的 Spring Security Core 和 Spring Security LDAP。

我们使用 Active Directory 进行身份验证,只有 2 或 3 人会使用这个小应用程序,所以似乎不值得为这个应用程序创建一个 AD 组。定义一个列表会更简单,只要有新员工而不是将他们添加到 AD 组,我所要做的就是将他们的名字添加到外部 Grails 配置中。

我想做如下的事情:

SomeController.groovy

@Secured("authentication.name in grailsApplication.config.my.app.usersList")
class SomeController {

}

然后在 Config.groovy 中放入这段代码:

my.app.usersList = ['Bill', 'Tom', 'Rick']

这可能吗?如果是这样,这是一个可怕的想法吗?非常感谢。

【问题讨论】:

  • 只是检查一下,您不需要用户具有不同的角色(如管理员)对吧?
  • 好问题,塞尔吉奥。否。访问此应用程序的任何用户都具有相同的角色。它是我们商务办公所需的数据库的简单 Web 前端。用户只会是我和少数商务办公人员。

标签: grails spring-security config


【解决方案1】:

这看起来很傻。为什么不在表中包含用户列表?然后,您可以在该表中添加/删除,而无需修改应用程序。

我目前正在这样做,并在我的UserDetailsContextMapper 中确保用户名已经存在于Users 表中。

【讨论】:

    【解决方案2】:

    您需要一个自定义身份验证器来尝试访问您的 Active Directory,如果经过身份验证,将查看 Grails 属性以检查用户名是否允许登录。

    这是我使用的类。我更改了代码以验证配置:

    class ActiveDirectoryAuthenticator {
    
      private DefaultSpringSecurityContextSource contextFactory
      private String principalSuffix = ""
    
      def grailsApplication
    
      public DirContextOperations authenticate(Authentication authentication) {
    
        // Grab the username and password out of the authentication object.
        String principal = authentication.getName() + "@" + principalSuffix
        String password = ""
        if (authentication.getCredentials() != null) {
          password = authentication.getCredentials().toString()
        }
    
        // If we have a valid username and password, try to authenticate.
        if (!("".equals(principal.trim())) && !("".equals(password.trim()))) {
    
          try {
    
            String provider  = contextFactory.getUrls()[0]
    
            Hashtable authEnv = new Hashtable(11)
            authEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory")
            authEnv.put(Context.PROVIDER_URL, provider)
            authEnv.put(Context.SECURITY_AUTHENTICATION, "simple")
            authEnv.put(Context.SECURITY_PRINCIPAL, principal)
            authEnv.put(Context.SECURITY_CREDENTIALS, password)
            javax.naming.directory.DirContext authContext = new InitialDirContext(authEnv)
    
    
            //here validate the user against your config.
            if(!authentication.getName() in grailsApplication.config.adUsersAllowed) {
              throw new BadCredentialsException("User not allowed.")
            }
    
            DirContextOperations authAdapter = new DirContextAdapter()
            authAdapter.addAttributeValue("ldapContext", authContext)
            return authAdapter
    
          } catch ( NamingException ex ) {
            throw new BadCredentialsException(ex.message)
          }
    
        } else {
          throw new BadCredentialsException("Incorrect username or password")
        }
      }
    
      public DefaultSpringSecurityContextSource getContextFactory() {
        return contextFactory
      }
    
      /**
       * Set the context factory to use for generating a new LDAP context.
       *
       * @param contextFactory
       */
      public void setContextFactory(DefaultSpringSecurityContextSource contextFactory) {
        this.contextFactory = contextFactory
      }
    
      public String getPrincipalSuffix() {
        return principalSuffix
      }
    
      /**
       * Set the string to be prepended to all principal names prior to attempting authentication
       * against the LDAP server.  (For example, if the Active Directory wants the domain-name-plus
       * backslash prepended, use this.)
       *
       * @param principalPrefix
       */
      public void setPrincipalSuffix(String principalSuffix) {
        if (principalSuffix != null) {
          this.principalSuffix = principalSuffix
        } else {
          this.principalSuffix = ""
        }
      }
    
    }
    

    在 resources.groovy 中将其声明为您的 ldapAuthenticator:

    ldapAuthenticator(ActiveDirectoryAuthenticator) {
      contextFactory = ref('contextSource')
      principalSuffix = 'domain.local' //your domain suffix
      grailsApplication = ref('grailsApplication')
    }
    

    缺点是在更改 config.groovy 时需要重新启动上下文

    在您的控制器中只需使用@Secured('IS_AUTHENTICATED_FULLY')

    【讨论】:

      【解决方案3】:

      我认为您不能这样做,因为注释是在编译时解决的,而不是在运行时解决的。配置属性将在应用程序运行时读取,所以我担心你最终不得不这样做:

      @Secured(["authentication.name in ['Bill', 'Tom', 'Rick']"])
      class SomeController {
      
      }
      

      【讨论】:

        【解决方案4】:

        如果我没记错的话,@Secured 注释除了比较角色之外不能用于其他用途。但是您应该可以使用 spring 证券 @PreAuthorize@PostAuthorize 注释来做到这一点。使用 grails 时,设置这些注释的最简单方法是安装 spring security ACL 插件。 在@PreAuthorize@PostAuthorize 中,您可以使用更灵活的SPEL 表达式。不幸的是,SPEL 不提供in 运算符。但是,您可以将安全检查委托给服务:

        @PreAuthorize('@securityService.canAccess(authentication)')
        public void test() {
            println "test?"
        }
        

        使用@ 符号,您可以在表达式中引用其他bean,例如服务。这里调用securityService.canAccess() 方法来评估登录用户是否可以访问该方法。 要使用它,您必须配置BeanResolver。我写了一些关于配置BeanResolverhere的更多细节。

        securityService 内,您现在可以:

        class SecurityService {
            def grailsApplication
            public boolean canAccess(Authentication auth) {
                return grailsApplication.config.myList.contains(auth.name)
            }    
        }
        

        一般来说,我不建议在安全检查中使用配置值来验证用户。 groovy 配置将被编译,因此您无法在不重新部署应用程序的情况下轻松添加新用户。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-12-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-26
          • 1970-01-01
          相关资源
          最近更新 更多