Grails Spring Security:如何让密码为null?

时间:2015-07-28 21:22:47

标签: grails spring-security

我正在使用Grails Spring Security Plugin。我要求对于某类用户,不需要密码。所以我在默认的用户域中覆盖了密码的约束:

class SecUser {
    ...    
    static constraints = {
        username blank: false, unique: true
        password blank: false, nullable: true
    }
    ...
}

但这会导致很多问题:

    用户域中断中的
  1. beforeInsert因为springSecurityService.encodePassword(password)无法接受空值;然后我覆盖beforeInsert

    def beforeInsert() {
        if (someCondition) {
            super.beforeInsert()
            passwordChangeDate = new Date()
        }
    }
    
  2. UserDetails分类因为构造函数无法接受密码作为空值,所以我覆盖了UserDetails

    import grails.plugin.springsecurity.userdetails.GrailsUser
    
    import org.springframework.security.core.GrantedAuthority
    import org.springframework.security.core.userdetails.User.AuthorityComparator
    import org.springframework.util.Assert
    
    class ILUserDetails extends GrailsUser {
    
        final String name
    
        ILUserDetails(String username, String password, boolean enabled,
            boolean accountNonExpired, boolean credentialsNonExpired,
            boolean accountNonLocked,
            Collection<GrantedAuthority> authorities,
            long id, String name) {
            //Override User 
            if (((username == null) || "".equals(username))) { // Allow null for password
                throw new IllegalArgumentException(
                    "Cannot pass null or empty values to constructor");
            }
    
            this.username = username;
            this.password = password;
            this.enabled = enabled;
            this.accountNonExpired = accountNonExpired;
            this.credentialsNonExpired = credentialsNonExpired;
            this.accountNonLocked = accountNonLocked;
            this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
            this.id=id
            this.name = name
        }
    
        private static SortedSet<GrantedAuthority> sortAuthorities(
            Collection<? extends GrantedAuthority> authorities) {
            Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
            // Ensure array iteration order is predictable (as per
            // UserDetails.getAuthorities() contract and SEC-717)
            SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet<GrantedAuthority>(
                new AuthorityComparator());
    
            for (GrantedAuthority grantedAuthority : authorities) {
                Assert.notNull(grantedAuthority,
                "GrantedAuthority list cannot contain any null elements");
                sortedAuthorities.add(grantedAuthority);
            }
    
            return sortedAuthorities;
        }
    }
    
  3. 然后我覆盖了beforeInsertUserDetails,发现了一个奇怪的错误:

    java.lang.NoSuchMethodError: grails.plugin.springsecurity.userdetails.GrailsUser: method <init>()V not found
    com.app.security.ILUserDetails.<init>(ILUserDetails.groovy)
    sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    org.springsource.loaded.ri.ReflectiveInterceptor.jlrConstructorNewInstance(ReflectiveInterceptor.java:986)
    org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:77)
    org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:102)
    org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:57)
    
  4. 现在,我不确定让密码可以为空可能是个好主意。有人可以给我一些建议吗?

1 个答案:

答案 0 :(得分:1)

之前的ILUserDetails有错误,因为子类无法访问私有属性。所以我根据UserGrailsUser.java重写了整个User.java课程。

//Rewrite according to GrailsUser and User
//https://github.com/spring-projects/spring-security/blob/master/core/src/main/java/org/springframework/security/core/userdetails/User.java
//https://github.com/grails-plugins/grails-spring-security-core/blob/master/src/java/grails/plugin/springsecurity/userdetails/GrailsUser.java
public class ILUser implements UserDetails, CredentialsContainer {
    private String password;
    private final String username;
    private final Set<GrantedAuthority> authorities;
    private final boolean accountNonExpired;
    private final boolean accountNonLocked;
    private final boolean credentialsNonExpired;
    private final boolean enabled;
    private static final long serialVersionUID = 1;
    private final Object id;
    private final String name;

    // ~ Constructors
    // ===================================================================================================

    /**
     * Construct the <code>User</code> with the details required by
     * {@link org.springframework.security.authentication.dao.DaoAuthenticationProvider}.
     *
     * @param password the password that should be presented to the
     * <code>DaoAuthenticationProvider</code>
     */
    public ILUser(String username, String password, boolean enabled,
            boolean accountNonExpired, boolean credentialsNonExpired,
            boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities, Object id, String name) {

        if (((username == null) || "".equals(username))) { // Here is the key line
            throw new IllegalArgumentException(
                    "Cannot pass null or empty values to constructor");
        }

        this.username = username;
        this.password = password;
        this.enabled = enabled;
        this.accountNonExpired = accountNonExpired;
        this.credentialsNonExpired = credentialsNonExpired;
        this.accountNonLocked = accountNonLocked;
        this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
        this.id = id;
        this.name = name;
    }

    // ~ Methods
    // ========================================================================================================

    public Collection<GrantedAuthority> getAuthorities() {
        return authorities;
    }

    public String getPassword() {
        return password;
    }

    public String getUsername() {
        return username;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public boolean isAccountNonExpired() {
        return accountNonExpired;
    }

    public boolean isAccountNonLocked() {
        return accountNonLocked;
    }

    public boolean isCredentialsNonExpired() {
        return credentialsNonExpired;
    }

    public void eraseCredentials() {
        password = null;
    }

    private static SortedSet<GrantedAuthority> sortAuthorities(
            Collection<? extends GrantedAuthority> authorities) {
        Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
        // Ensure array iteration order is predictable (as per
        // UserDetails.getAuthorities() contract and SEC-717)
        SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet<GrantedAuthority>(
                new AuthorityComparator());

        for (GrantedAuthority grantedAuthority : authorities) {
            Assert.notNull(grantedAuthority,
                    "GrantedAuthority list cannot contain any null elements");
            sortedAuthorities.add(grantedAuthority);
        }

        return sortedAuthorities;
    }

    private static class AuthorityComparator implements Comparator<GrantedAuthority>,
            Serializable {
        private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

        public int compare(GrantedAuthority g1, GrantedAuthority g2) {
            // Neither should ever be null as each entry is checked before adding it to
            // the set.
            // If the authority is null, it is a custom authority and should precede
            // others.
            if (g2.getAuthority() == null) {
                return -1;
            }

            if (g1.getAuthority() == null) {
                return 1;
            }

            return g1.getAuthority().compareTo(g2.getAuthority());
        }
    }

    /**
     * Returns {@code true} if the supplied object is a {@code User} instance with the
     * same {@code username} value.
     * <p>
     * In other words, the objects are equal if they have the same username, representing
     * the same principal.
     */
    @Override
    public boolean equals(Object rhs) {
        if (rhs instanceof ILUser) {
            return username.equals(((ILUser) rhs).username);
        }
        return false;
    }

    /**
     * Returns the hashcode of the {@code username}.
     */
    @Override
    public int hashCode() {
        return username.hashCode();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(super.toString()).append(": ");
        sb.append("Username: ").append(this.username).append("; ");
        sb.append("Password: [PROTECTED]; ");
        sb.append("Enabled: ").append(this.enabled).append("; ");
        sb.append("AccountNonExpired: ").append(this.accountNonExpired).append("; ");
        sb.append("credentialsNonExpired: ").append(this.credentialsNonExpired)
                .append("; ");
        sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");

        if (!authorities.isEmpty()) {
            sb.append("Granted Authorities: ");

            boolean first = true;
            for (GrantedAuthority auth : authorities) {
                if (!first) {
                    sb.append(",");
                }
                first = false;

                sb.append(auth);
            }
        }
        else {
            sb.append("Not granted any authorities");
        }

        return sb.toString();
    }

    /**
     * Get the id.
     * @return the id
     */
    public Object getId() {
        return id;
    }
}