spring security 3.0x 使用

  本文是一个简单的基于用户,角色,权限的spring security应用。

   使用步骤:

   1 在web.xml引入如下配置:

     

	<listener>  
	    <listener-class>
	    org.springframework.security.web.session.HttpSessionEventPublisher
	    </listener-class>  
	</listener> 

    

   2 增加spring security配置文件spring_security.xml(名称可以自己取):

    

<b:beans xmlns="http://www.springframework.org/schema/security"
 xmlns:b="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="false" access-denied-page="/accessDenied.jsp">
	  <!-- 不要过滤图片等静态资源,其中**代表可以跨越目录,*不可以跨越目录。
	  <intercept-url pattern="/**/*.jpg" filters="none" />
	  <intercept-url pattern="/**/*.png" filters="none" />
	  <intercept-url pattern="/**/*.gif" filters="none" />
	  <intercept-url pattern="/**/*.css" filters="none" />
	  <intercept-url pattern="/**/*.js" filters="none" /> -->
	  <!-- 登录页面和忘记密码页面不过滤 -->
	  <intercept-url pattern="/login.jsp" filters="none" />
	  <intercept-url pattern="/jsp/forgotpassword.jsp"   filters="none" />
	  <!-- ROLE_ENTER_ORDINARY_PAGE, -->
	  <intercept-url pattern="/index.jsp"   access="ROLE_ENTER_ORDINARY_PAGE, ROLE_ENTER_HIGH_LEVEL_PAGE" /> 
	
	  
	  <!-- 检测失效的sessionId,超时时定位到另外一个URL, 防止固化session攻击 -->
	  <!-- <session-management invalid-session-url="/timeout.jsp" session-fixation-protection="migrateSession"> -->
	  <session-management session-authentication-strategy-ref="sessionAuthenticationStrategy">
   	  </session-management>
   	  
   	  <custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" /> 
	  
	  <form-login login-page="/login.jsp" authentication-failure-url="/loginError.jsp"   default-target-url="/index.jsp"/>
	  <logout invalidate-session="true" logout-success-url="/login.jsp"/>
	  <http-basic/>
	  <!-- <remember-me user-service-ref="userService"/> -->
	  <remember-me user-service-ref="userService" data-source-ref="myDataSource"/>
	  <anonymous/>
	 </http>

	 <!-- 注意能够为authentication-manager 设置alias别名  -->
	 <authentication-manager alias="authenticationManager">
	      <!-- <authentication-provider user-service-ref="userDetailsManager"> -->
	      <authentication-provider user-service-ref="userService">
      		<password-encoder hash="md5">
      			<salt-source user-property="username"/>
      		</password-encoder>
	           <!-- <password-encoder ref="passwordEncoder"> -->
	                <!-- 用户名做为盐值 -->
	                <!--<salt-source user-property="username" />
	           </password-encoder>-->
	      </authentication-provider>
	 </authentication-manager>
	 

	 
</b:beans>

    

   3 在web.xml中添加spring security配置的引用

    

  	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/spring.xml, /WEB-INF/spring/spring_security.xml</param-value>
	</context-param>

   4 创建用户,角色,权限表

   

--创建表t_user
create table t_user(
id int PRIMARY key auto_increment,
username VARCHAR(50) not null,
password varchar(50) not NULL
);
--插入数据
insert into t_user values(null, 'user', '47a733d60998c719cf3526ae7d106d13');
insert into t_user values(null, 'admin', 'ceb4f32325eda6142bd65215f4c0f371');

--创建表t_Role
create table 	(
id int PRIMARY key auto_increment,
name VARCHAR(50) not null
);
--插入数据
insert into t_role values(null, '普通用户');
insert into t_role values(null, '高级用户');


--创建表t_Perm
create table t_perm(
id int PRIMARY key auto_increment,
name VARCHAR(50) not null
);

--插入数据
insert into t_perm values(null, 'ROLE_ENTER_ORDINARY_PAGE');
insert into t_perm values(null, 'ROLE_ENTER_HIGH_LEVEL_PAGE');



--创建表角色--人员的关联关系(多对多)
create table t_user_role(
id int primary key auto_increment,
userid int not null, 
roleid int not null
);

--创建约束
alter table t_user_role
add CONSTRAINT fk_userid foreign key (userid)
REFERENCES t_user (id);

alter table t_user_role
add CONSTRAINT fk_roleid foreign key (roleid)
REFERENCES t_role (id);

--插入数据
insert into t_user_role
select null,a.id, b.id   from t_user a, t_role b 
where a.username = 'user' and b.name='普通用户';

insert into t_user_role
select null,a.id, b.id   from t_user a, t_role b 
where a.username = 'admin' and b.name='高级用户';




--创建角色--权限关联关系表(多对多)
create table t_role_perm(
id int primary key auto_increment,
permid int not null, 
roleid int not null
);


--创建约束
alter table t_role_perm
add CONSTRAINT fk_perm_permid foreign key (permid)
REFERENCES t_perm (id);

alter table t_role_perm
add CONSTRAINT fk_perm_roleid foreign key (roleid)
REFERENCES t_role (id);

--插入数据
insert into t_role_perm
select null,a.id, b.id   from t_role a, t_perm b 
where a.name = '普通用户' and b.name='ENTER_ORDINARY_PAGE';

insert into t_role_perm
select null,a.id, b.id   from t_role a, t_perm b 
where a.name = '高级用户' and b.name='ROLE_ENTER_HIGH_LEVEL_PAGE';

  5 在spring security的配置文件中,有如下配置:

	 <authentication-manager alias="authenticationManager">
	      <!-- <authentication-provider user-service-ref="userDetailsManager"> -->
	      <authentication-provider user-service-ref="userService">
      		<password-encoder hash="md5">
      			<salt-source user-property="username"/>
      		</password-encoder>
	           <!-- <password-encoder ref="passwordEncoder"> -->
	                <!-- 用户名做为盐值 -->
	                <!--<salt-source user-property="username" />
	           </password-encoder>-->
	      </authentication-provider>
	 </authentication-manager>

   对于authentication-provider的配置有很多种,可以使用jdbc的配置,也可以使用service的,在此,我们使用service配置来实现用户的登陆和授权验证

   

  6 在spring的配置文件中注册要使用的service

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/context 
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">

  <!-- 配置占位符 -->
  <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">    
    <property name="location" >   
        <value>WEB-INF/config/jdbc.properties</value>  
    </property>  
  </bean>   
  
  <!-- 数据源 -->
  <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${JDBC.DRIVERNAME}"/>
    <property name="url" value="${JDBC.URL}"/>
    <property name="username" value="${JDBC.USERNAME}"/>
    <property name="password" value="${JDBC.PASSWORD}"/>
  </bean>
    

  <bean id="mySessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="myDataSource"/>
      
    <property name="packagesToScan">
    	<list>
    		<value>main.model</value>
    	</list>
    </property>
    <property name="hibernateProperties">
      <value>
        hibernate.dialect=org.hibernate.dialect.MySQLDialect
        hibernate.show_sql=true
        hibernate.hbm2ddl.auto=update
        hibernate.cache.provider_class=org.hibernate.cache.NoCacheProvider
      </value>
    </property>
  </bean>  
  <bean id="userDaoImpl" class="main.daoImpl.UserDaoImpl">
  	<property name="sessionFactory" ref="mySessionFactory"></property>
  </bean>
  
  
   <bean id="passwordEncoder"
  	class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />
  	
  	 <!-- 用户详细信息管理 : 数据源、用户缓存、启用用户组功能。  -->
	 <bean id="userDetailsManager"
	  class="org.springframework.security.provisioning.JdbcUserDetailsManager">
	  <property name="dataSource" ref="myDataSource" />
	  <!--  <property name="userCache" ref="userCache" /> -->
	 </bean> 
	 
	 <bean id="userService" class="main.service.UserService">
	 	<property name="userDaoImpl" ref="userDaoImpl"/>
	 </bean>

	<!-- spring security session-manager -->
	<bean id="concurrencyFilter"  
	    class="org.springframework.security.web.session.ConcurrentSessionFilter">  
	    <property name="sessionRegistry" ref="sessionRegistry" />  
	    <property name="expiredUrl" value="/timeout.jsp" /> 
	</bean> 

	<bean id="sessionAuthenticationStrategy"  
    	class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">  
	    <constructor-arg type="org.springframework.security.core.session.SessionRegistry" index="0"
	        ref="sessionRegistry" />  
	    <property name="maximumSessions" value="1" />  
	    <property name="exceptionIfMaximumExceeded" value="true"></property>
	</bean>  
	
	<bean id="sessionRegistry"  
	    class="org.springframework.security.core.session.SessionRegistryImpl" />
	 
</beans>

   

  7 使用UserDetailsService做验证和授权,首先要实现UserDetails接口,以把我们从数据库查询到的数据包装后供spring security使用

package main.security;

import java.util.ArrayList;
import java.util.Collection;

import main.model.Perm;
import main.model.User;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.userdetails.UserDetails;

@SuppressWarnings("serial")
public class UserDetail implements UserDetails {
	
	public UserDetail(User user) {
		this.username = user.getUsername();
		this.password = user.getPassword();
		this.authorities = new ArrayList<GrantedAuthority>();
		for (Perm perm : user.getPerms()) {
			this.authorities.add(new GrantedAuthorityImpl(perm.getName()));
		}
	}
	
	private String username;
	
	private String password;
	
	private Collection<GrantedAuthority> authorities;

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

	public String getPassword() {
		return this.password;
	}

	public String getUsername() {
		return this.username;
	}

	public boolean isAccountNonExpired() {
		return true;
	}

	public boolean isAccountNonLocked() {
		return true;
	}

	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof UserDetail) {
			UserDetail another = (UserDetail)obj;
			return this.getUsername().equals(another.getUsername());
		}
		return super.equals(obj);
	}

	@Override
	public int hashCode() {
		return this.getUsername().hashCode();
	}

	public boolean isEnabled() {
		return true;
	}
	

}

   在UserDetails中可以获取到当前用户的权限

  8 实现UserDetailsService接口,实现验证和授权

   

package main.service;

import java.util.List;

import main.daoImpl.UserDaoImpl;
import main.model.Perm;
import main.model.User;
import main.security.UserDetail;

import org.springframework.dao.DataAccessException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class UserService implements UserDetailsService {

	private UserDaoImpl userDaoImpl;

	public void setUserDaoImpl(UserDaoImpl userDaoImpl) {
		this.userDaoImpl = userDaoImpl;
	}

	public UserDetails loadUserByUsername(String username)
    	throws UsernameNotFoundException, DataAccessException {
		User user = this.userDaoImpl.findByName(username);
		if (user == null) {
			throw new UsernameNotFoundException("用户名错误!");
		}
		//从数据库中获取当前用户拥有权限
		List<Perm> permList = this.userDaoImpl.listPermByUser(user);
		user.setPerms(permList);
		return new UserDetail(user);
	}

}

   看到loadUserByUsername方法时,你可能会疑问,只是在验证用户名是否正确,并没验证密码,是的,此方法只验证用户名,返回值类为UserRetails,该接口有个getPassword()方法,实现该接口时只要把用户的密码在此方法中返回就行了,密码的验证由spring security 自己完成的

 到此就是一个完整的基于用户,角色,权限管理的spring security项目了,有很多的具体细节没有讲到,我在此附上源码,有兴趣的可以自己跑跑一下!

猜你喜欢

转载自abc08010051.iteye.com/blog/1998233