Grails Spring Security:如何允许密码为空?
Posted
技术标签:
【中文标题】Grails Spring Security:如何允许密码为空?【英文标题】:Grails Spring Security: how can I allow the password null? 【发布时间】:2015-10-19 15:51:58 【问题描述】:我正在使用 Grails Spring 安全插件。我有一个要求,对于一种用户,不需要密码。所以我覆盖了默认用户域中的密码约束:
class SecUser
...
static constraints =
username blank: false, unique: true
password blank: false, nullable: true
...
但这会导致很多问题:
用户域中的beforeInsert
中断,因为springSecurityService.encodePassword(password)
不能接受空值;然后我覆盖beforeInsert
:
def beforeInsert()
if (someCondition)
super.beforeInsert()
passwordChangeDate = new Date()
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;
然后我覆盖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)
现在,我不确定让密码可以为空是否是个好主意。有人能给我一些建议吗?
【问题讨论】:
【参考方案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;
【讨论】:
以上是关于Grails Spring Security:如何允许密码为空?的主要内容,如果未能解决你的问题,请参考以下文章
在 Spring Security 登录期间设置 Grails/Spring Locale - 如何?
Grails Spring-Security - 如何比较密码-
使用 Spring Security 时如何允许 CKEditor 在 Grails 中上传图像
如何使用 spring-security-core-ldap 插件在 grails 中实现 LDAP 身份验证?