`
jusesgod
  • 浏览: 52198 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

SSH框架结合Spring Security3新手入门

阅读更多
想给自己的程序加点安全控制,网上查了一下,说Spring Security是时下最流行,与spring结合的最好的安全框架,就决定去试一下。

使用的Spring Security版本是 3.0.5,它对Spring的版本是有要求的,Spring的版本必须在3.0以上,于是更新了下Spring环境,去官网下一个就行了,我用的是3.0.5版本号与Spring Security的版本正好相同。
Sping3本质上与Spring2没有什么区别,配置文件也不用动,主要就是Spring原来的核心包被拆成了小块,所有的功能现在都可以灵活的添加了。话虽如此,但其实也不是把所有的dist目录下的包全导进去就行了,网上查了一下,除了下面两个包:
org.springframework.web.struts-3.0.5.RELEASE.jar
org.springframework.web.portlet-3.0.5.RELEASE.jar
不要导入,另外还要添加一个日志相关包commons-logging和一个aopalliance的包就可以正常运作了。
======================================================================
接下来我们正式进入Spring Security3的配置
我的数据库结构不同于"参考手册"上的默认配置,都是用Hibernate进行映射构建的,以下是类的代码:
Ⅰ.Account类存储用户的信息
package cn.com.jusesgod.domain.security;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

@Entity
public class Account implements UserDetails{
	/**
	 * 
	 */
	private static final long serialVersionUID = 5275764647347461532L;
	
	private String username; //用户名
	private String password; //密码
	private boolean enable; //是否可用
	private Set<Authorities> grantedAuthorities; //表示用户所拥有的权限
	private int total; //玩这个游戏的总局数
	private int win; //赢的局数
	private int lose; //输的局数
	private int flee; //逃走的局数
	
	public Account(){}
	
	public Account(String username,String password){
		this.username = username;
		this.password = password;
		this.total = 0;
		this.win = 0;
		this.lose = 0;
		this.flee = 0;
	}
	
	public Account(String username,String password,int total,int win,int lose,int flee, Collection<GrantedAuthority> authorities){
		this.username = username;
		this.password = password;
		this.total = total;
		this.win = win;
		this.lose = lose;
		this.flee = flee;
		this.enable = true;
		grantedAuthorities = new HashSet<Authorities>();
		for(GrantedAuthority t : authorities){
			grantedAuthorities.add(new Authorities(this.username,t.getAuthority()));
		}
	}
	
	public void strat(){
		total += 1;
	}
	
	public void setFlee(int flee) {
		this.flee = flee;
	}

	public void setLose(int lose) {
		this.lose = lose;
	}

	public void setTotal(int total) {
		this.total = total;
	}

	public void setWin(int win) {
		this.win = win;
	}

	public void win(){
		win += 1;
	}
	
	public void lose(){
		lose += 1;
	}
	
	public void flee(){
		flee += 1;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Id
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public int getTotal() {
		return total;
	}

	public int getWin() {
		return win;
	}

	public int getLose() {
		return lose;
	}

	public int getFlee() {
		return flee;
	}
	
	@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)	//FetchType.EAGER表示立刻加载
	@JoinTable(name="authorities",
			joinColumns=@JoinColumn(name="username"))
	public Set<Authorities> getGrantedAuthorities() {
		return grantedAuthorities;
	}
	
	@Transient
	public Set<GrantedAuthority> getAuthorities() {
		Set<GrantedAuthority> ga = new HashSet<GrantedAuthority>();
		for(Authorities temp : grantedAuthorities){
			ga.add(temp);
		}
		return ga;
	}

	public void setGrantedAuthorities(Set<Authorities> authorities) {
		this.grantedAuthorities = authorities;
	}

	public boolean isEnable() {
		return enable;
	}

	public void setEnable(boolean enable) {
		this.enable = enable;
	}

	@Transient
	public boolean isAccountNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	@Transient
	public boolean isAccountNonLocked() {
		// TODO Auto-generated method stub
		return true;
	}

	@Transient
	public boolean isCredentialsNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	@Transient
	public boolean isEnabled() {
		return enable;
	}
}


Ⅱ.Authorities对应Account中的grantedAuthorities属性,使用联合主键,有两个class文件共同实现
package cn.com.jusesgod.domain.security;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;

import org.springframework.security.core.GrantedAuthority;

@Entity
@IdClass(AuthoritiesPK.class)
public class Authorities implements GrantedAuthority {
	private String username;
	private String authority;

	public Authorities(){}
	
	public Authorities(String username,String authority){
		this.username = username;
		this.authority = authority;
	}
	
	public void setAuthority(String authority) {
		this.authority = authority;
	}

	@Id
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Id
	public String getAuthority() {
		return authority;
	}
}

package cn.com.jusesgod.domain.security;

import java.io.Serializable;

import javax.persistence.Embeddable;

@Embeddable
public class AuthoritiesPK implements Serializable {
	private String username;
	private String authority;

	public AuthoritiesPK(){}
	
	public AuthoritiesPK(String username,String authority){
		this.username = username;
		this.authority = authority;
	}	
	
	public void setAuthority(String authority) {
		this.authority = authority;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getAuthority() {
		return authority;
	}
}


1.配置web.xml文件,照着参考文档我们添加如下几个标签
<filter>
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>


2.用Spring配置Spring Security,我写了两个文件进行配置
第一个用了命名空间,主要配置Spring Security的主体
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  		xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.0.xsd">
           
    <http auto-config="true" access-denied-page="/error.html">
    	<intercept-url pattern="/login.*" filters="none"/>
    	<intercept-url pattern="/role_*" access="ROLE_USER"/>
    	<form-login login-page="/login.html" default-target-url="/role_hall.html" authentication-failure-url="/login.jsp"/>
    	<custom-filter ref="authenticationFilter" before="FORM_LOGIN_FILTER"/>
    	<!-- 
    		第二次登录阻止,用户会被转发到 form-login 标签里定义的  authentication-failure-url 的地址
    		如果是form-base登录,用户会被转发到 session-management 中 session-authention-error-url 的地址
    		session-fixation-protection 防止Session固定攻击(2.3.3.3)
    			-migrateSession 创建一个新的session,把原来session中所有属性复制到新session中。这是默认值
    			-none 什么也不做
    			-newSession 创建一个新的"干净的"session,不会复制session中的数据。
    	 -->
    	<session-management session-fixation-protection="migrateSession" invalid-session-url="/error.html">
    		<!--
    			max-session
    			error-if-maxinum-exceeded
    		 -->
    		<concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>
    	</session-management>
    </http>
    
    <authentication-manager>
    	<authentication-provider  user-service-ref="accoutJDBCImpl">
    	</authentication-provider>
    </authentication-manager>
    
    <global-method-security secured-annotations="enabled" jsr250-annotations="enabled"></global-method-security>
    
</beans:beans>

另一个用来配置其中用到的注入类的声明
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"  
	   xmlns:security="http://www.springframework.org/schema/security"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
        xmlns:aop="http://www.springframework.org/schema/aop"  
         xmlns:tx="http://www.springframework.org/schema/tx"  
         xmlns:context="http://www.springframework.org/schema/context"  
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd   
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd   
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.0.xsd">

	<bean id="authenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
		
		<property name="authenticationManager" ref="authenticationManager"></property>
		<property name="filterProcessesUrl" value="/j_spring_security_check"></property>
	</bean>
	<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
		<property name="providers">
			<list>
				<ref local="daoAuthenticationProvider"/>
			</list>
		</property>
	</bean>
	<bean id="daoAuthenticationProvider" class="cn.com.jusesgod.authentication.provider.MyDaoAuthenticationProvider">
		<property name="userDetailsService" ref="accoutJDBCImpl"></property>
	</bean>
	<bean id="accoutJDBCImpl" class="cn.com.jusesgod.service.impl.AccountJDBCImpl">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<bean id="authenticationProcessingFilterEntryPoint"   
    	class="org.springframework.security.web.authentication.AuthenticationProcessingFilterEntryPoint">   
    	<property name="loginFormUrl" value="/login"></property>   
	</bean>  
</beans>


3.可以看出来,上面有些注入的类是我自己自定义的,为了让我的数据结构能够让Spring Security识别,我对如下几个默认组件进行了修改,然后添加到了框架中,下面附上代码

MyDaoAuthenticationProvider
package cn.com.jusesgod.authentication.provider;

import org.springframework.dao.DataAccessException;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.util.Assert;

public class MyDaoAuthenticationProvider extends
		AbstractUserDetailsAuthenticationProvider {

	 private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();

	    private SaltSource saltSource;

	    private UserDetailsService userDetailsService;

	    private boolean includeDetailsObject = true;

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

	    protected void additionalAuthenticationChecks(UserDetails userDetails,
	            UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
	        Object salt = null;

	        if (this.saltSource != null) {
	            salt = this.saltSource.getSalt(userDetails);
	        }

	        if (authentication.getCredentials() == null) {
	            logger.debug("Authentication failed: no credentials provided");

	            throw new BadCredentialsException(messages.getMessage(
	                    "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
	                    includeDetailsObject ? userDetails : null);
	        }

	        String presentedPassword = authentication.getCredentials().toString();
	        logger.debug("presentedPassword:" + presentedPassword);
	        logger.debug("userDetails.getPassword():" + userDetails.getPassword());
	        System.out.println(presentedPassword);
	        
	        if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
	            logger.debug("Authentication failed: password does not match stored value");

	            throw new BadCredentialsException(messages.getMessage(
	                    "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
	                    includeDetailsObject ? userDetails : null);
	        }
	    }

	    protected void doAfterPropertiesSet() throws Exception {
	        Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
	    }

	    protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
	            throws AuthenticationException {
	        UserDetails loadedUser;

	        try {
	            loadedUser = this.getUserDetailsService().loadUserByUsername(username);
	        }
	        catch (DataAccessException repositoryProblem) {
	            throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
	        }

	        if (loadedUser == null) {
	            throw new AuthenticationServiceException(
	                    "UserDetailsService returned null, which is an interface contract violation");
	        }
	        return loadedUser;
	    }

	    /**
	     * Sets the PasswordEncoder instance to be used to encode and validate passwords.
	     * If not set, {@link PlaintextPasswordEncoder} will be used by default.
	     *
	     * @param passwordEncoder The passwordEncoder to use
	     */
	    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
	        this.passwordEncoder = passwordEncoder;
	    }

	    protected PasswordEncoder getPasswordEncoder() {
	        return passwordEncoder;
	    }

	    /**
	     * The source of salts to use when decoding passwords. <code>null</code>
	     * is a valid value, meaning the <code>DaoAuthenticationProvider</code>
	     * will present <code>null</code> to the relevant <code>PasswordEncoder</code>.
	     *
	     * @param saltSource to use when attempting to decode passwords via the <code>PasswordEncoder</code>
	     */
	    public void setSaltSource(SaltSource saltSource) {
	        this.saltSource = saltSource;
	    }

	    protected SaltSource getSaltSource() {
	        return saltSource;
	    }

	    public void setUserDetailsService(UserDetailsService userDetailsService) {
	        this.userDetailsService = userDetailsService;
	    }

	    protected UserDetailsService getUserDetailsService() {
	        return userDetailsService;
	    }

	    protected boolean isIncludeDetailsObject() {
	        return includeDetailsObject;
	    }

	    /**
	     * Determines whether the UserDetails will be included in the <tt>extraInformation</tt> field of a
	     * thrown BadCredentialsException. Defaults to true, but can be set to false if the exception will be
	     * used with a remoting protocol, for example.
	     *
	     * @deprecated use {@link org.springframework.security.authentication.ProviderManager#setClearExtraInformation(boolean)}
	     */
	    public void setIncludeDetailsObject(boolean includeDetailsObject) {
	        this.includeDetailsObject = includeDetailsObject;
	    }

}


AccountJDBCImpl
package cn.com.jusesgod.service.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.context.ApplicationContextException;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.Assert;

import cn.com.jusesgod.domain.security.Account;

/**
 * <tt>UserDetailsServiceRetrieves</tt> implementation which retrieves the user details
 * (username, password, enabled flag, and authorities) from a database using JDBC queries.
 * UserDetailsServiceRettrieves
 * 	实现了如何去得到用用户的信息(username,password,enabled flag,和authorite)通过JDBC查询获取数据源
 *
 * <h3>Default Schema</h3>
 * 	默认的模式
 * A default database schema is assumed, with two tables "users" and "authorities".
 *	一个默认的数据模式被设定,有两个表"user"和"authorities"
 * <h4>The Users table</h4>
 *	User表
 * This table contains the login name, password and enabled status of the user.
 *
 * <table>
 * <tr><th>Column</th></tr>
 * <tr><td>username</td></tr>
 * <tr><td>password</td></tr>
 * <tr><td>enabled</td></tr>
 * </table>
 *
 * <h4>The Authorities Table</h4>
 *	Authorities表
 * <table>
 * <tr><th>Column</th></tr>
 * <tr><td>username</td></tr>
 * <tr><td>authority</td></tr>
 * </table>
 *
 * If you are using an existing schema you will have to set the queries <tt>usersByUsernameQuery</tt> and
 * <tt>authoritiesByUsernameQuery</tt> to match your database setup
 * 	如果你使用一个存在的模式,你必须设置查询方法"usersByUsernameQuery"和"authoritiesByUsernameQuery"去适应你的数据源设置
 * (see {@link #DEF_USERS_BY_USERNAME_QUERY} and {@link #DEF_AUTHORITIES_BY_USERNAME_QUERY}).
 *	查看这两个变量会有帮助
 *
 * <p>
 * In order to minimise backward compatibility issues, this implementation doesn't recognise the expiration of user
 * accounts or the expiration of user credentials. However, it does recognise and honour the user enabled/disabled
 * column. This should map to a <tt>boolean</tt> type in the result set (the SQL type will depend on the
 * database you are using). All the other columns map to <tt>String</tt>s.
 * 	为了尽量减少向后兼容性的问题,这个实现不关心用户账户的期限或者用户证书的期限。而只关心注意用户是否可用(enable/disable列),这需要设置成一个
 * boolean的类型在返回的设置里(在数据库保存的SQL属性取决于你的数据库)所有其他的属性使用String类型
 *
 * <h3>Group Support</h3>
 * 组权限支持
 * Support for group-based authorities can be enabled by setting the <tt>enableGroups</tt> property to <tt>true</tt>
 * (you may also then wish to set <tt>enableAuthorities</tt> to <tt>false</tt> to disable loading of authorities
 * directly). With this approach, authorities are allocated to groups and a user's authorities are determined based
 * on the groups they are a member of. The net result is the same (a UserDetails containing a set of
 * <tt>GrantedAuthority</tt>s is loaded), but the different persistence strategy may be more suitable for the
 * administration of some applications.
 * <p>
 * 	对于支持组权限,我们需要设置enableGroups属性为true(你应当还希望去设置enableAuthorities为false去阻止导入authorities表中的权限设置)
 * 	通过这种方法,权限被分成一组一组的,并且用户的权限被通过组的方法确定他们归属于那一个权限组。网络要求同样的(一个UserDetails包含
 * 	一个GrantedAuthority的设置被读取),但是不同的应用可能需要不同的持久化策略。
 * 
 * When groups are being used, the tables "groups", "group_members" and "group_authorities" are used. See
 * {@link #DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY} for the default query which is used to load the group authorities.
 * Again you can customize this by setting the <tt>groupAuthoritiesByUsernameQuery</tt> property, but the format of
 * the rows returned should match the default.
 * 	当组权限被使用,表groups,group_members和group_authorities也被使用。参看DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY属性,了解
 * 	默认的组权限查询语句。
 * 	同样,你可以去自定义这个属性通过设置groupAuthoritiesByUsernameQuery属性,但是返回的结果列会被格式化成默认的形式。
 *
 * @author Ben Alex
 * @author colin sampaleanu
 * @author Luke Taylor
 */
public class AccountJDBCImpl extends JdbcDaoSupport implements UserDetailsService {
//	~ Static fields/initializers =====================================================================================

    public static final String DEF_USERS_BY_USERNAME_QUERY =
            "select username,password,enable " +
            "from Account " +
            "where username = ?";
    public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =
            "select username,authority " +
            "from Authorities " +
            "where username = ?";
    public static final String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY =
            "select g.id, g.group_name, ga.authority " +
            "from groups g, group_members gm, group_authorities ga " +
            "where gm.username = ? " +
            "and g.id = ga.group_id " +
            "and g.id = gm.group_id";

    //~ Instance fields ================================================================================================

    protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();

    private String authoritiesByUsernameQuery;
    private String groupAuthoritiesByUsernameQuery;
    private String usersByUsernameQuery;
    private String rolePrefix = "";
    private boolean usernameBasedPrimaryKey = true;
    private boolean enableAuthorities = true;
    private boolean enableGroups = false;

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

    public AccountJDBCImpl() {
        usersByUsernameQuery = DEF_USERS_BY_USERNAME_QUERY;
        authoritiesByUsernameQuery = DEF_AUTHORITIES_BY_USERNAME_QUERY;
        groupAuthoritiesByUsernameQuery = DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY;
    }

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

    /**
     * Allows subclasses to add their own granted authorities to the list to be returned in the <tt>UserDetails</tt>.
     *  允许子类添加他们自己的授权权限到列表里,在UserDetails里面被返回。
     *
     * @param username the username, for use by finder methods
     * @param authorities the current granted authorities, as populated from the <code>authoritiesByUsername</code>
     *        mapping
     */
    protected void addCustomAuthorities(String username, List<GrantedAuthority> authorities) {
    	
    }

    public String getUsersByUsernameQuery() {
        return usersByUsernameQuery;
    }

    protected void initDao() throws ApplicationContextException {
    	//确保两个权限模式必有一个在使用
        Assert.isTrue(enableAuthorities || enableGroups, "Use of either authorities or groups must be enabled");
    }

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
        List<UserDetails> users = loadUsersByUsername(username);
        
        if (users.size() == 0) {
            logger.debug("Query returned no results for user '" + username + "'");

            throw new UsernameNotFoundException(
                    messages.getMessage("JdbcDaoImpl.notFound", new Object[]{username}, "Username {0} not found"), username);
        }

        UserDetails user = users.get(0); // contains no GrantedAuthority[]

        Set<GrantedAuthority> dbAuthsSet = new HashSet<GrantedAuthority>();

        if (enableAuthorities) {
            dbAuthsSet.addAll(loadUserAuthorities(user.getUsername()));
        }

        if (enableGroups) {
            dbAuthsSet.addAll(loadGroupAuthorities(user.getUsername()));
        }

        List<GrantedAuthority> dbAuths = new ArrayList<GrantedAuthority>(dbAuthsSet);

        addCustomAuthorities(user.getUsername(), dbAuths);

        if (dbAuths.size() == 0) {
            logger.debug("User '" + username + "' has no authorities and will be treated as 'not found'");

            throw new UsernameNotFoundException(
                    messages.getMessage("JdbcDaoImpl.noAuthority",
                            new Object[] {username}, "User {0} has no GrantedAuthority"), username);
        }

        System.out.println("dbAuths:" + dbAuths.get(0).getAuthority());
        return createUserDetails(username, user, dbAuths);
    }

    /**
     * Executes the SQL <tt>usersByUsernameQuery</tt> and returns a list of UserDetails objects.
     * There should normally only be one matching user.
     */
    protected List<UserDetails> loadUsersByUsername(String username) {
        return getJdbcTemplate().query(usersByUsernameQuery, new String[] {username}, new RowMapper<UserDetails>() {
            public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException {
                String username = rs.getString(1);
                String password = rs.getString(2);
                return new Account(username,password,0,0,0,0,new HashSet<GrantedAuthority>());
            }
        });
    }

    /**
     * Loads authorities by executing the SQL from <tt>authoritiesByUsernameQuery</tt>.
     *
     * @return a list of GrantedAuthority objects for the user
     */
    protected List<GrantedAuthority> loadUserAuthorities(String username) {
        return getJdbcTemplate().query(authoritiesByUsernameQuery, new String[] {username}, new RowMapper<GrantedAuthority>() {
            public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException {
                String roleName = rolePrefix + rs.getString(2);
                logger.debug("row authorities:" + roleName + " to " + rs.getString(1));
                GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);

                return authority;
            }
        });
    }

    /**
     * Loads authorities by executing the SQL from <tt>groupAuthoritiesByUsernameQuery</tt>.
     *
     * @return a list of GrantedAuthority objects for the user
     */
    protected List<GrantedAuthority> loadGroupAuthorities(String username) {
        return getJdbcTemplate().query(groupAuthoritiesByUsernameQuery, new String[] {username}, new RowMapper<GrantedAuthority>() {
            public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException {
                 String roleName = getRolePrefix() + rs.getString(3);
                 GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);

                 return authority;
            }
        });
    }

    /**
     * Can be overridden to customize the creation of the final UserDetailsObject which is
     * returned by the <tt>loadUserByUsername</tt> method.
     *
     * @param username the name originally passed to loadUserByUsername
     * @param userFromUserQuery the object returned from the execution of the
     * @param combinedAuthorities the combined array of authorities from all the authority loading queries.
     * @return the final UserDetails which should be used in the system.
     */
    protected UserDetails createUserDetails(String username, UserDetails userFromUserQuery,
            List<GrantedAuthority> combinedAuthorities) {
        String returnUsername = userFromUserQuery.getUsername();

        if (!usernameBasedPrimaryKey) {
            returnUsername = username;
        }

        logger.debug("username = " + returnUsername);
        logger.debug("password = " + userFromUserQuery.getPassword());
        return new Account(returnUsername, userFromUserQuery.getPassword(), 0,
                0, 0, 0,combinedAuthorities);
    }

    /**
     * Allows the default query string used to retrieve authorities based on username to be overridden, if
     * default table or column names need to be changed. The default query is {@link
     * #DEF_AUTHORITIES_BY_USERNAME_QUERY}; when modifying this query, ensure that all returned columns are mapped
     * back to the same column names as in the default query.
     *
     * @param queryString The SQL query string to set
     */
    public void setAuthoritiesByUsernameQuery(String queryString) {
        authoritiesByUsernameQuery = queryString;
    }

    protected String getAuthoritiesByUsernameQuery() {
        return authoritiesByUsernameQuery;
    }

    /**
     * Allows the default query string used to retrieve group authorities based on username to be overridden, if
     * default table or column names need to be changed. The default query is {@link
     * #DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY}; when modifying this query, ensure that all returned columns are mapped
     * back to the same column names as in the default query.
     *
     * @param queryString The SQL query string to set
     */
    public void setGroupAuthoritiesByUsernameQuery(String queryString) {
        groupAuthoritiesByUsernameQuery = queryString;
    }

    /**
     * Allows a default role prefix to be specified. If this is set to a non-empty value, then it is
     * automatically prepended to any roles read in from the db. This may for example be used to add the
     * <tt>ROLE_</tt> prefix expected to exist in role names (by default) by some other Spring Security
     * classes, in the case that the prefix is not already present in the db.
     *
     * @param rolePrefix the new prefix
     */
    public void setRolePrefix(String rolePrefix) {
        this.rolePrefix = rolePrefix;
    }

    protected String getRolePrefix() {
        return rolePrefix;
    }

    /**
     * If <code>true</code> (the default), indicates the {@link #getUsersByUsernameQuery()} returns a username
     * in response to a query. If <code>false</code>, indicates that a primary key is used instead. If set to
     * <code>true</code>, the class will use the database-derived username in the returned <code>UserDetails</code>.
     * If <code>false</code>, the class will use the {@link #loadUserByUsername(String)} derived username in the
     * returned <code>UserDetails</code>.
     *
     * @param usernameBasedPrimaryKey <code>true</code> if the mapping queries return the username <code>String</code>,
     *        or <code>false</code> if the mapping returns a database primary key.
     */
    public void setUsernameBasedPrimaryKey(boolean usernameBasedPrimaryKey) {
        this.usernameBasedPrimaryKey = usernameBasedPrimaryKey;
    }

    protected boolean isUsernameBasedPrimaryKey() {
        return usernameBasedPrimaryKey;
    }

    /**
     * Allows the default query string used to retrieve users based on username to be overridden, if default
     * table or column names need to be changed. The default query is {@link #DEF_USERS_BY_USERNAME_QUERY}; when
     * modifying this query, ensure that all returned columns are mapped back to the same column names as in the
     * default query. If the 'enabled' column does not exist in the source database, a permanent true value for this
     * column may be returned by using a query similar to
     * <pre>
     * "select username,password,'true' as enabled from users where username = ?"
     * </pre>
     *
     * @param usersByUsernameQueryString The query string to set
     */
    public void setUsersByUsernameQuery(String usersByUsernameQueryString) {
        this.usersByUsernameQuery = usersByUsernameQueryString;
    }

    protected boolean getEnableAuthorities() {
        return enableAuthorities;
    }

    /**
     * Enables loading of authorities (roles) from the authorities table. Defaults to true
     */
    public void setEnableAuthorities(boolean enableAuthorities) {
        this.enableAuthorities = enableAuthorities;
    }

    protected boolean getEnableGroups() {
        return enableGroups;
    }

    /**
     * Enables support for group authorities. Defaults to false
     * @param enableGroups
     */
    public void setEnableGroups(boolean enableGroups) {
        this.enableGroups = enableGroups;
    }
}


页面的制作,可以自己添加几个简单的进行尝试,注意login表单里面用户名的name要用j_username,password的name要用j_password,action的url要写"<%=path %>/j_spring_security_check"

经过如上配置,所有的role_开头的资源都会被保护,需要用户登录,且拥有"ROLE_USER"的权限才可以查阅,我们可以自己去数据库添加用户添加权限来进行登录。

我的主要参考是Spring Security-3.0.1中文官方文档,然后查看Spring Security包里面的源码会有很大的帮助。
1
6
分享到:
评论

相关推荐

    forum_0116_1535.rar

    SSH框架在JavaWeb开发中是十分重要的一个组合,它由Spring、Struts和Hibernate三个开源框架构成,提供了全面的企业级应用解决方案。这个"forum_0116_1535.rar"压缩包中可能包含了一个基于SSH框架的论坛系统的源代码...

    sblim-gather-provider-2.2.8-9.el7.x64-86.rpm.tar.gz

    1、文件内容:sblim-gather-provider-2.2.8-9.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/sblim-gather-provider-2.2.8-9.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、更多资源/技术支持:公众号禅静编程坊

    基于pringboot框架的图书进销存管理系统的设计与实现(Java项目编程实战+完整源码+毕设文档+sql文件+学习练手好项目).zip

    本图书进销存管理系统管理员功能有个人中心,用户管理,图书类型管理,进货订单管理,商品退货管理,批销订单管理,图书信息管理,客户信息管理,供应商管理,库存分析管理,收入金额管理,应收金额管理,我的收藏管理。 用户功能有个人中心,图书类型管理,进货订单管理,商品退货管理,批销订单管理,图书信息管理,客户信息管理,供应商管理,库存分析管理,收入金额管理,应收金额管理。因而具有一定的实用性。 本站是一个B/S模式系统,采用Spring Boot框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得图书进销存管理系统管理工作系统化、规范化。本系统的使用使管理人员从繁重的工作中解脱出来,实现无纸化办公,能够有效的提高图书进销存管理系统管理效率。 关键词:图书进销存管理系统;Spring Boot框架;MYSQL数据库

    2024中国在人工智能领域的创新能力如何研究报告.pdf

    2024中国在人工智能领域的创新能力如何研究报告.pdf

    安全生产_人脸识别_移动目标跟踪_智能管控平台技术实现与应用_1741777778.zip

    人脸识别项目实战

    人脸识别_TF2_Facenet_训练预测应用仓库_1741778670.zip

    人脸识别项目实战

    安全人脸识别_对抗攻击_多模型集成_减少扰动_竞赛方案_Ne_1741779504.zip

    人脸识别项目实战

    Python实现基于CEEMDAN完全自适应噪声集合经验模态分解时间序列信号分解的详细项目实例(含完整的程序,GUI设计和代码详解)

    内容概要:本文档详细介绍了基于CEEMDAN(完全自适应噪声集合经验模态分解)的方法实现时间序列信号分解的具体项目。文中涵盖项目背景介绍、主要目标、面临的挑战及解决方案、技术创新点、应用领域等多方面内容。项目通过多阶段流程(数据准备、模型设计与构建、性能评估、UI设计),并融入多项关键技术手段(自适应噪声引入、并行计算、机器学习优化等)以提高非线性非平稳信号的分析质量。同时,该文档包含详细的模型架构描述和丰富的代码样例(Python代码),有助于开发者直接参考与复用。 适合人群:具有时间序列分析基础的科研工作者、高校教师与研究生,从事信号处理工作的工程技术人员,或致力于数据科学研究的从业人员。 使用场景及目标:此项目可供那些面临时间序列数据中噪声问题的人群使用,尤其适用于需从含有随机噪音的真实世界信号里提取有意义成分的研究者。具体场景包括但不限于金融市场趋势预测、设备故障预警、医疗健康监控以及环境质量变动跟踪等,旨在提供一种高效的信号分离和分析工具,辅助专业人士进行精准判断和支持决策。 其他说明:本文档不仅限于理论讲解和技术演示,更着眼于实际工程项目落地应用,强调软硬件资源配置、系统稳定性测试等方面的细节考量。通过完善的代码实现说明以及GUI界面设计指南,使读者能够全面理解整个项目的开发流程,同时也鼓励后续研究者基于已有成果继续创新拓展,探索更多的改进空间与发展机遇。此外,针对未来可能遇到的各种情况,提出了诸如模型自我调整、多模态数据融合等发展方向,为长期发展提供了思路指导。

    监护人,小孩和玩具数据集 4647张原始图片 监护人 食物 孩子 玩具 精确率可达85.4% pasical voc xml格式

    监护人,小孩和玩具数据集 4647张原始图片 监护人 食物 孩子 玩具 精确率可达85.4% pasical voc xml格式

    根据提供的内容可以构建以下_1741777949.zip

    人脸识别项目实战

    `计算机视觉_人脸识别_Python_OpenCV_树莓派毕业设计`.zip

    人脸识别项目实战

    智慧生产企业园区解决方案PPT(54页).pptx

    在智慧园区建设的浪潮中,一个集高效、安全、便捷于一体的综合解决方案正逐步成为现代园区管理的标配。这一方案旨在解决传统园区面临的智能化水平低、信息孤岛、管理手段落后等痛点,通过信息化平台与智能硬件的深度融合,为园区带来前所未有的变革。 首先,智慧园区综合解决方案以提升园区整体智能化水平为核心,打破了信息孤岛现象。通过构建统一的智能运营中心(IOC),采用1+N模式,即一个智能运营中心集成多个应用系统,实现了园区内各系统的互联互通与数据共享。IOC运营中心如同园区的“智慧大脑”,利用大数据可视化技术,将园区安防、机电设备运行、车辆通行、人员流动、能源能耗等关键信息实时呈现在拼接巨屏上,管理者可直观掌握园区运行状态,实现科学决策。这种“万物互联”的能力不仅消除了系统间的壁垒,还大幅提升了管理效率,让园区管理更加精细化、智能化。 更令人兴奋的是,该方案融入了诸多前沿科技,让智慧园区充满了未来感。例如,利用AI视频分析技术,智慧园区实现了对人脸、车辆、行为的智能识别与追踪,不仅极大提升了安防水平,还能为园区提供精准的人流分析、车辆管理等增值服务。同时,无人机巡查、巡逻机器人等智能设备的加入,让园区安全无死角,管理更轻松。特别是巡逻机器人,不仅能进行360度地面全天候巡检,还能自主绕障、充电,甚至具备火灾预警、空气质量检测等环境感知能力,成为了园区管理的得力助手。此外,通过构建高精度数字孪生系统,将园区现实场景与数字世界完美融合,管理者可借助VR/AR技术进行远程巡检、设备维护等操作,仿佛置身于一个虚拟与现实交织的智慧世界。 最值得关注的是,智慧园区综合解决方案还带来了显著的经济与社会效益。通过优化园区管理流程,实现降本增效。例如,智能库存管理、及时响应采购需求等举措,大幅减少了库存积压与浪费;而设备自动化与远程监控则降低了维修与人力成本。同时,借助大数据分析技术,园区可精准把握产业趋势,优化招商策略,提高入驻企业满意度与营收水平。此外,智慧园区的低碳节能设计,通过能源分析与精细化管理,实现了能耗的显著降低,为园区可持续发展奠定了坚实基础。总之,这一综合解决方案不仅让园区管理变得更加智慧、高效,更为入驻企业与员工带来了更加舒适、便捷的工作与生活环境,是未来园区建设的必然趋势。

    第八届全国大学生创新创业年会-创新创业展示项目集

    本届年会的主题是“青春梦想创新创业”。通过学术论文报告、创新创业项目展示、创业项目推介、工作研讨、联谊活动、大会报告等活动,全面展示大学生最新的创新创业成果。年会共收到491所高校推荐的学术论文756篇、创新创业展示项目721项、创业推介项目156项,合计1633项,为历届年会数量最高。经过36所“985”高校相关学科专家的初评以及国家级大学生创新创业训练计划专家组的复选,最终遴选出可参加本次年会的学术论文180篇,创新创业展示项目150个,创业推介项目45项,共计375项,涉及30个省市的236所高校。年会还收到了来自澳门特别行政区、俄罗斯的13项学术论文及参展项目。这些材料集中反映了各高校最新的创新创业教育成果,也直接体现了当代大学生的创新思维和实践能力。

    人脸识别_实时_ArcFace_多路识别技术_JavaScr_1741771263.zip

    人脸识别项目实战

    6ES7215-1AG40-0XB0-V04.04.01固件4.5

    6ES7215-1AG40-0XB0_V04.04.01固件4.5

    在无人机上部署SchurVins的yaml配置文件

    在无人机上部署SchurVins的yaml配置文件

    uniapp实战商城类app和小程序源码​​​​​​.rar

    uniapp实战商城类app和小程序源码,包含后端API源码和交互完整源码。

    基于MobileNet轻量级网络实现的常见30多种食物分类

    基于MobileNet轻量级网络实现的常见30多种食物分类,包含数据集、训练脚本、验证脚本、推理脚本等等。 数据集总共20k左右,推理的形式是本地的网页推理

    2024年央国企RPA市场研究报.pdf

    2024年央国企RPA市场研究报.pdf

    VSCodeSetup-x64-1.98.0.rar

    VSCodeSetup-x64-1.98.0.rar vscode是一种简化且高效的代码编辑器,同时支持诸如调试,任务执行和版本管理之类的开发操作。它的目标是提供一种快速的编码编译调试工具。然后将其余部分留给IDE。vscode集成了所有一款现代编辑器所应该具备的特性,包括语法高亮、可定制的热键绑定、括号匹配、以及代码片段收集等。 Visual Studio Code(简称VSCode)是Microsoft开发的代码编辑器,它支持Windows,Linux和macOS等操作系统以及开源代码。它支持测试,并具有内置的Git版本控制功能以及开发环境功能,例如代码完成(类似于IntelliSense),代码段和代码重构等。编辑器支持用户定制的配置,例如仍在编辑器中时,可以更改各种属性和参数,例如主题颜色,键盘快捷键等,内置的扩展程序管理功能。

Global site tag (gtag.js) - Google Analytics