欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【CAS】自定义多条件查询配置

程序员文章站 2024-03-05 16:01:07
...
【回顾】
	在上一篇博客中,总结了cas server的自定义登录页面配置以及返回更多的用户信息给客户端,本篇博客将
总结cas server的自定义多条件查询配置。
【背景】
	在cas框架中,默认的登录验证就只是通过用户名和密码。而在实际应用中,我们也许会遇到一些其它的查
询条件,例如邮箱、手机号等也可以登录;或者我们不仅仅需要验证用户名,还需要增加某个验证条件。
【需求】
	在此项目中,因为涉及到多个租户,难免可能会有租户的用户名相同的情况存在,所以,我们需要增加一项
验证条件,即该用户所属租户的名称。
【步骤】
	1. 扩展认证条件类,增加company字段。
	在cas-server-core的源码中,定义了一个认证的类,其中声明了用户名和密码,即认证的条件。如下:
				
	增加一个条件,首先需要扩展该类,所以我们可以在此类中增加一个company字段,表示认证用户的所属
单位。代码如下:

	public class UsernamePasswordCredential implements Credential, Serializable {
	
	    /** Unique ID for serialization. */
	    private static final long serialVersionUID = -700605081472810939L;
	
	    /** Password suffix appended to username in string representation. */
	    private static final String PASSWORD_SUFFIX = "+password";
	
	    /** The username. */
	    @NotNull
	    @Size(min=1, message = "required.username")
	    private String username;
	
	    /** The password. */
	    @NotNull
	    @Size(min=1, message = "required.password")
	    private String password;
	    
	    /** The company. */
	    @NotNull
	    @Size(min=1,message = "required.company")
	    private String company;
	
		public String getCompany() {
			return company;
		}
	
		public void setCompany(final String company) {
			this.company = company;
		}
	
	    /** Default constructor. */
	    public UsernamePasswordCredential() {}
	
	    /**
	     * Creates a new instance with the given username and password and company.
	     *
	     * @param userName Non-null user name.
	     * @param password Non-null password.
	     * @param password Non-null company.
	     */
	    public UsernamePasswordCredential(final String userName, final String password,final String company) {
	        this.username = userName;
	        this.password = password;
	        this.company=company;
	    }
	
	    /**
	     * @return Returns the password.
	     */
	    public final String getPassword() {
	        return this.password;
	    }
	
	    /**
	     * @param password The password to set.
	     */
	    public final void setPassword(final String password) {
	        this.password = password;
	    }
	
	    /**
	     * @return Returns the userName.
	     */
	    public final String getUsername() {
	        return this.username;
	    }
	
	    /**
	     * @param userName The userName to set.
	     */
	    public final void setUsername(final String userName) {
	        this.username = userName;
	    }
	
	    /** {@inheritDoc} */
	    @Override
	    public String getId() {
	        return this.username;
	    }
	
	    @Override
	    public String toString() {
	        return this.username + PASSWORD_SUFFIX;
	    }
	
	    @Override
	    public boolean equals(final Object o) {
	        if (this == o) {
	            return true;
	        }
	        if (o == null || getClass() != o.getClass()) {
	            return false;
	        }
	
	        UsernamePasswordCredential that = (UsernamePasswordCredential) o;
	
	        if (password != null ? !password.equals(that.password) : that.password != null) {
	            return false;
	        }
	
	        if (username != null ? !username.equals(that.username) : that.username != null) {
	            return false;
	        }
	        
	        if (company != null ? !company.equals(that.company) : that.company != null) {
	            return false;
	        }
	
	        return true;
	    }
	
	    @Override
	    public int hashCode() {
	        int result = username != null ? username.hashCode() : 0;
	        result = 31 * result + (password != null ? password.hashCode() : 0);
	        return result;
	    }

}
	2. 扩展查询数据库认证类,由单条件查询扩展为多条件查询。

	在deployerConfigContext.xml文件中,我们可以发现数据库配置的处理类是
QueryDatabaseAuthenticationHandler. 该类在cas-server-support-jdbc源码中可以找到,
	那么我们的任务便是在源码中自定义一个多条件查询类,在配置文件中使用我们自己写的类去进行数据库认
证。如下:
			
	MultiQueryDatabaseAuthenticationHandler代码如下:

	public class MultiQueryDatabaseAuthenticationHandler extends AbstractJdbcUsernamePasswordAuthenticationHandler{
	
		@NotNull
	    private String sql;
	
	    /** {@inheritDoc} */
	    @Override
	    protected final HandlerResult authenticateUsernamePasswordInternal(final UsernamePasswordCredential credential)
	            throws GeneralSecurityException, PreventedException {
	
	        final String username = credential.getUsername();
	//        新添加的Company
	        final String company=credential.getCompany();
	        
	        final String encryptedPassword = this.getPasswordEncoder().encode(credential.getPassword());
	        try {
	            final String dbPassword = getJdbcTemplate().queryForObject(this.sql, String.class, 
	            		//username和company为查询条件字段
	            		username,company);
	            
	    		if (!dbPassword.equals(encryptedPassword)) {
	                throw new FailedLoginException("Password does not match value on record.");
	            }
	        	    
	        } catch (final IncorrectResultSizeDataAccessException e) {
	            if (e.getActualSize() == 0) {
	                throw new AccountNotFoundException(username + " not found with SQL query");
	            } else {
	                throw new FailedLoginException("Multiple records found for " + username + company);
	            }
	        } catch (final DataAccessException e) {
	            throw new PreventedException("SQL exception while executing query for " + username + company, e);
	        }
	        return createHandlerResult(credential, new SimplePrincipal(username), null);
	    }
	
	    /**
	     * @param sql The sql to set.
	     */
	    public void setSql(final String sql) {
	        this.sql = sql;
	    }
	
	}
	3. 修改cas-server-webapp源码中的login-webflow.xml文件,增加登录页面form表单绑定的学校属性,
如下:

     

	4. 修改cas-server-webapp源码中的deployerConfigContext.xml文件,使用自定义的多条件查询认证处理
类:
	<!-- 密码加密方式-->
	    <bean id="passwordEncoder"
	      class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder"
	      c:encodingAlgorithm="MD5"
	      p:characterEncoding="UTF-8" />
	      <bean id="dbAuthHandler"
	      class="org.jasig.cas.adaptors.jdbc.MultiQueryDatabaseAuthenticationHandler"
	      p:dataSource-ref="dataSource"
	      p:sql="select a.password from ta_allusers a INNER JOIN ta_registuser b 
ON a.registUserId = b.id where a.userCode=? and a.isDelete=0 and b.isDelete=0 and b.companyName=? " 
		  p:passwordEncoder-ref="passwordEncoder" />
	5. 修改结果如下,用户名、密码和学校名称三个条件认证成功,才能登录:
			
	用户名和密码正确,但学校名称不正确,无法登录:

			
【总结】
	修改认证条件,这也应该是实际应用中常见的问题。我们在平时使用其他软件的时候,也可以感受到,用户
登录的条件不仅仅只有用户名一种,也可以利用自己注册时的手机号或邮箱进行认证。多一种方式,也给用户多了提
供了一份便利。不论是“或”还是“与”条件,则必然需要对其源代码进行扩展。从源码中可以进一步帮助我们理解
此框架流程,阅读源码也是一种升华。


相关标签: CAS 多条件查询