【问题标题】:customising authentication in Spring Security在 Spring Security 中自定义身份验证
【发布时间】:2014-01-12 03:11:02
【问题描述】:

在我的 Grails 应用程序中,我使用 Spring Security 插件并定义了 custom userDetailsService Spring bean 以控制如何检索用户和角色数据,例如

class MyUserDetailsService implements GrailsUserDetailsService {

    /**
     * Some Spring Security classes (e.g. RoleHierarchyVoter) expect at least one role, so
     * we give a user with no granted roles this one which gets past that restriction but
     * doesn't grant anything.
     */
    static final List NO_ROLES = [new GrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE)]

    UserDetails loadUserByUsername(String username, boolean loadRoles) {
        return loadUserByUsername(username)
    }

    UserDetails loadUserByUsername(String username) {
        User.withTransaction { status ->

            User user = User.findByUsername(username)
            if (!user) {
                throw new UsernameNotFoundException('User not found', username)
            }

            def authorities = user.authorities.collect {new GrantedAuthorityImpl(it.authority)}
            return new CustomUserDetails(
                    user.username,
                    user.password,
                    user.enabled,
                    !user.accountExpired,
                    !user.passwordExpired,
                    !user.accountLocked,
                    authorities ?: NO_ROLES,
                    user.id,
                    user.name)
        }
    }
}

上面引用的CustomUserDetails 类只是用name 字段扩展GrailsUser

class CustomUserDetails extends GrailsUser {

    private static final long serialVersionUID = 1;

    final String name

    CustomUserDetails(String username,
                      String password,
                      boolean enabled,
                      boolean accountNonExpired,
                      boolean credentialsNonExpired,
                      boolean accountNonLocked,
                      Collection<GrantedAuthority> authorities,
                      long id,
                      String displayName) {

        super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities, id)
        this.name = displayName
    }
}

除了自定义用户和角色数据的检索方式之外,我还想控制用户的身份验证方式。在我的情况下,身份验证过程并不像通常的“检查输入的密码是否与数据库中的密码匹配”那么简单。用户如何通过身份验证的实际细节无关紧要,因此为了简单起见,我们假设如果用户的 name 字段与输入的密码匹配,则他被授予封装在 CustomUserDetails 中的角色(权限)。

我想插件中的某个地方有一个 Spring bean,我可以覆盖它以自定义默认身份验证机制,但是哪个?因为name字段仅由CustomUserDetails定义,所以我需要访问MyUserDetailsService返回的这个类的实例才能执行自定义身份验证,这可能吗?

【问题讨论】:

    标签: grails spring-security grails-plugin


    【解决方案1】:

    我在这里讨论了自定义登录,示例应用的代码:http://burtbeckwith.com/blog/?p=1090

    但是,如果您只想为用户授予与数据库中不同的角色,我会在MyUserDetailsService 中执行此操作。不需要角色在数据库中——Spring Security 只需要一堆GrantedAuthorityImpl 实例。在我开发的一个应用程序中,我在身份验证期间自动将 ROLE_USER 授予常规站点用户,以避免浪费数据库空间。

    编辑:

    如果您使用 DaoAuthenticationProvider,您可以通过自定义 preAuthenticationChecks 和/或 postAuthenticationChecks bean 在身份验证期间添加其他检查。子类化插件中的那些并添加您自己的检查,并将它们注册到 resources.groovy 为

    preAuthenticationChecks(MyPreAuthenticationChecks)
    postAuthenticationChecks(MyPostAuthenticationChecks)
    

    【讨论】:

    • 不寻常的不是角色分配,而是用户身份验证 - 我更新了示例下方的第一段,以更接近真实流程。感谢您的回复,我会看看您博文中的示例项目。
    • 感谢您的更新。我注意到在您的示例项目中,您将附加检查直接放在 AuthenticationProvider 中,而不是扩展前检查或后检查,有什么理由吗?此外,在 Spring Security 中,实际的身份验证检查发生在哪里,即检查输入的密码是否与存储的密码匹配?
    • 没有太多原因 - Spring Security 中的 impl 必须具有一定的灵活性和可定制性,但示例代码更能代表特定用例的 impl。对于DaoAuthenticationProvider,密码检查位于additionalAuthenticationChecks,锁定/过期检查发生在preAuthenticationChecks.check()postAuthenticationChecks.check()
    猜你喜欢
    • 2014-04-20
    • 2014-12-13
    • 2016-08-05
    • 2020-12-05
    • 2015-04-27
    • 2016-07-24
    • 2016-09-05
    • 2021-04-21
    • 2016-10-31
    相关资源
    最近更新 更多