springsecurity with grails-如何拒绝使用逻辑删除属性删除的用户登录

springsecurity with grails-如何拒绝使用逻辑删除属性删除的用户登录,grails,spring-security,Grails,Spring Security,我正在使用Grails2.2.2和spring安全内核:2.0-RC2 我的域用户对象实际上并没有从数据库中删除,而是将一个名为“deleted”的属性设置为true 问题是:如何阻止spring security向标记为已删除的用户id授予成功登录尝试 我希望能够支持使用以前删除的名称创建新用户 Burt Beckwith下面的回答让我开始检查覆盖spring安全bean实现的方法 我已经尝试用如下所示的实现覆盖userDetailsService bean和springSecuritySer

我正在使用Grails2.2.2和spring安全内核:2.0-RC2

我的域用户对象实际上并没有从数据库中删除,而是将一个名为“deleted”的属性设置为true

问题是:如何阻止spring security向标记为已删除的用户id授予成功登录尝试

我希望能够支持使用以前删除的名称创建新用户

Burt Beckwith下面的回答让我开始检查覆盖spring安全bean实现的方法

我已经尝试用如下所示的实现覆盖userDetailsService bean和springSecurityService中的两个方法(我所做的只是使用相同的父类实现,但将User.findWhere()方法更改为使用deleted:false)

我还将这些bean定义添加到resources.groovy中,但我发现有时会调用原始的SpringSecurityService.getCurrentUser()方法,而不是我的实现。(如果我将spring安全源更改为我的实现,这一切都可以正常工作,但我宁愿使用覆盖,以便将来的版本升级不会中断)


这是没有测试,但应该工作或非常接近工作

您需要覆盖插件注册的
preAuthenticationChecks
springbean中的逻辑。默认实现执行
isAccountNonLocked()
isEnabled()
isAccountNonExpired()
检查,因此您可以将其子类化并添加检查:

将它放在与您选择的包相对应的/src/groovy目录的子目录中,并在
grails app/conf/spring/resources.groovy中注册您的包:

import com.foo.bar.MyPreAuthenticationChecks

beans = {
   preAuthenticationChecks(MyPreAuthenticationChecks)
}

请注意,您将使用的“用户”实例是
UserDetails
实例,而不是加载以填充
UserDetails
的域类实例。因此,要访问
deleted
属性,您还需要一个自定义
UserDetailsService
。这很简单,也是一件很常见的事情,因此在文档中有自己的章节:


请注意,将异常作为静态内部类、使用单例以及重写
fillInStackTrace
方法都是可选的,与此问题无关。如果愿意的话,您可以将它放在自己的顶级类中(对我来说,将它保持在内部是有意义的,因为它不太可能在这个类之外使用)。您还可以每次创建一个新实例,但实例之间没有区别(没有有用的状态),因此不需要这样做。我覆盖到
fillInStackTrace
,以避免在根本不需要这些堆栈帧时产生填充所有这些堆栈帧的成本。

很晚了,但如果它为某人服务,那么它就是:


简化Burt Beckwith的回答,如果您只想抛出与用户不存在时相同的异常,您可以像这样扩展
DefaultPreAuthenticationChecks
(其中Person是用户的表),而不需要自定义
UserDetailsService

import grails.plugin.springsecurity.userdetails.DefaultPreAuthenticationChecks;
import org.springframework.security.core.userdetails.UserDetails;
import  org.springframework.security.core.userdetails.UsernameNotFoundException;

class MyPreAuthenticationChecks extends DefaultPreAuthenticationChecks {

  void check(UserDetails user) {

    // do the standard checks
    super.check user

    if (Person.findByUsername(user.getUsername())?.deleted){
        log.debug("Wrong credentials");
        throw new UsernameNotFoundException("Wrong credentials");
    }
  }
}

这看起来真的很有希望,但我担心它不会涵盖一种情况:如果我创建一个用户名为xyz的用户,然后将其删除怎么办。然后使用相同的用户名xyz创建另一个新用户。我支持这一观点。似乎此修复程序只会在从数据库中查找用户对象后检查删除标志。我希望在数据库中查找用户名的查询只排除deleted=true的记录。我正在研究您为此提到的UserDetails服务,但我还没有让它工作。
UserDetails服务
肯定是这样做的地方-只需在查询中添加额外的条件以排除已删除的用户。
package com.foo.bar

import grails.plugin.springsecurity.userdetails.DefaultPreAuthenticationChecks
import org.springframework.security.authentication.AccountStatusException

class MyPreAuthenticationChecks extends DefaultPreAuthenticationChecks {

   private static final EXCEPTION = new DeletedException()

   void check(UserDetails user) {

      // do the standard checks
      super.check user

      // then the custom check(s)
      if (user.deleted) {
         log.debug 'User account is deleted'
         throw EXCEPTION
      }
   }

   static class DeletedException extends AccountStatusException {
      LockedException() {
         super('User account is deleted')
      }

      // avoid the unnnecessary cost
      Throwable fillInStackTrace() {
         this
      }
   }
}
import com.foo.bar.MyPreAuthenticationChecks

beans = {
   preAuthenticationChecks(MyPreAuthenticationChecks)
}
import grails.plugin.springsecurity.userdetails.DefaultPreAuthenticationChecks;
import org.springframework.security.core.userdetails.UserDetails;
import  org.springframework.security.core.userdetails.UsernameNotFoundException;

class MyPreAuthenticationChecks extends DefaultPreAuthenticationChecks {

  void check(UserDetails user) {

    // do the standard checks
    super.check user

    if (Person.findByUsername(user.getUsername())?.deleted){
        log.debug("Wrong credentials");
        throw new UsernameNotFoundException("Wrong credentials");
    }
  }
}