【问题标题】:Grails Spring Security: how can I allow the password null?Grails Spring Security:如何允许密码为空?
【发布时间】:2015-10-19 15:51:58
【问题描述】:

我正在使用 Grails Spring 安全插件。我有一个要求,对于一种用户,不需要密码。所以我覆盖了默认用户域中的密码约束:

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. 然后我覆盖beforeInsert和UserDetails,一个奇怪的bug发生了:

    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)
    

现在,我不确定让密码可以为空是否是个好主意。有人能给我一些建议吗?

【问题讨论】:

    标签: grails spring-security


    【解决方案1】:

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

    //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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-07-29
      • 1970-01-01
      • 1970-01-01
      • 2012-04-10
      • 2013-11-21
      • 2012-09-12
      • 2016-01-01
      • 2015-10-01
      • 2015-01-08
      相关资源
      最近更新 更多