`

spring security3进级篇III

 
阅读更多

      在spring security3进级篇II中,虽然将用户和权限存入到数据库中,但在配置文件中仍然要对URL地址配置角色进行控制访问,如何将用户,角色,资源存放到数据库中,进行统一管理,逐步实现RBAC的模型呢,这需要更复杂的实现,这一篇将实现将所有的信息存储到数据库中,但不涉及组,许可等表。

 

1、首先建立数据表

CREATE DATABASE IF NOT EXISTS spring_securityiii;
USE spring_securityiii;

--
-- Definition of table `pub_resources`
--

DROP TABLE IF EXISTS `pub_resources`;
CREATE TABLE `pub_resources` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `resource_name` varchar(50) NOT NULL,
  `resource_type` varchar(50) NOT NULL,
  `resource_string` varchar(200) NOT NULL,
  `resource_enabled` tinyint(1) NOT NULL,
  `resource_desc` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_pub_resource` (`resource_name`)
) ENGINE=InnoDB AUTO_INCREMENT=402 DEFAULT CHARSET=utf8;

--
-- Dumping data for table `pub_resources`
--

/*!40000 ALTER TABLE `pub_resources` DISABLE KEYS */;
INSERT INTO `pub_resources` (`id`,`resource_name`,`resource_type`,`resource_string`,`resource_enabled`,`resource_desc`) VALUES 
 (400,'index页面','url','/index.*',1,'index页面'),
 (401,'admin页面','url','/admin.*',1,'admin页面');
/*!40000 ALTER TABLE `pub_resources` ENABLE KEYS */;


--
-- Definition of table `pub_roles`
--

DROP TABLE IF EXISTS `pub_roles`;
CREATE TABLE `pub_roles` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(100) NOT NULL,
  `role_enabled` tinyint(1) NOT NULL,
  `role_desc` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_pub_role` (`role_name`)
) ENGINE=InnoDB AUTO_INCREMENT=202 DEFAULT CHARSET=utf8;

--
-- Dumping data for table `pub_roles`
--

/*!40000 ALTER TABLE `pub_roles` DISABLE KEYS */;
INSERT INTO `pub_roles` (`id`,`role_name`,`role_enabled`,`role_desc`) VALUES 
 (200,'ROLE_ADMIN',1,'管理员角色'),
 (201,'ROLE_USER',1,'普通用户角色');
/*!40000 ALTER TABLE `pub_roles` ENABLE KEYS */;


--
-- Definition of table `pub_roles_resources`
--

DROP TABLE IF EXISTS `pub_roles_resources`;
CREATE TABLE `pub_roles_resources` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `role_id` bigint(20) NOT NULL,
  `resource_id` bigint(20) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `roles_resources_ibfk_1` (`role_id`),
  KEY `roles_resources_ibfk_2` (`resource_id`),
  CONSTRAINT `roles_resources_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `pub_roles` (`id`),
  CONSTRAINT `roles_resources_ibfk_2` FOREIGN KEY (`resource_id`) REFERENCES `pub_resources` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=503 DEFAULT CHARSET=utf8;

--
-- Dumping data for table `pub_roles_resources`
--

/*!40000 ALTER TABLE `pub_roles_resources` DISABLE KEYS */;
INSERT INTO `pub_roles_resources` (`id`,`role_id`,`resource_id`) VALUES 
 (500,200,400),
 (501,200,401),
 (502,201,400);
/*!40000 ALTER TABLE `pub_roles_resources` ENABLE KEYS */;


--
-- Definition of table `pub_users`
--

DROP TABLE IF EXISTS `pub_users`;
CREATE TABLE `pub_users` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_account` varchar(50) NOT NULL,
  `user_password` varchar(20) NOT NULL,
  `user_enabled` tinyint(1) NOT NULL,
  `user_desc` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_pub_user` (`user_account`)
) ENGINE=InnoDB AUTO_INCREMENT=102 DEFAULT CHARSET=utf8;

--
-- Dumping data for table `pub_users`
--

/*!40000 ALTER TABLE `pub_users` DISABLE KEYS */;
INSERT INTO `pub_users` (`id`,`user_account`,`user_password`,`user_enabled`,`user_desc`) VALUES 
 (100,'admin','admin',1,'管理员'),
 (101,'user','user',1,'普通用户');
/*!40000 ALTER TABLE `pub_users` ENABLE KEYS */;


--
-- Definition of table `pub_users_roles`
--

DROP TABLE IF EXISTS `pub_users_roles`;
CREATE TABLE `pub_users_roles` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL,
  `role_id` bigint(20) NOT NULL,
  `ur_enabled` tinyint(1) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `users_roles_ibfk_1` (`user_id`),
  KEY `users_roles_ibfk_2` (`role_id`),
  CONSTRAINT `users_roles_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `pub_users` (`id`),
  CONSTRAINT `users_roles_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `pub_roles` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=303 DEFAULT CHARSET=utf8;

--
-- Dumping data for table `pub_users_roles`
--

/*!40000 ALTER TABLE `pub_users_roles` DISABLE KEYS */;
INSERT INTO `pub_users_roles` (`id`,`user_id`,`role_id`,`ur_enabled`) VALUES 
 (300,100,200,1),
 (301,100,201,1),
 (302,101,201,1);
/*!40000 ALTER TABLE `pub_users_roles` ENABLE KEYS */;

 2、自定义实现spring security的四个类

 

package com.spring.security.service.impl;

import javax.annotation.Resource;

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import com.spring.security.dao.UserDao;
import com.spring.security.domain.User;
import com.spring.security.service.CustomUserDetailsService;

@Service("customUserDetailsService")
public class CustomUserDetailsServiceImpl implements CustomUserDetailsService {
	
	@Resource
	private UserDao userDao;

	@Override
	public UserDetails loadUserByUsername(String userName)throws UsernameNotFoundException {
		
		User user = userDao.findUserByName(userName);
		
		if (user == null) {
			throw new UsernameNotFoundException("用户名" + userName + "不存在");
		}

		// 因为User已经实现了UserDetails接口,所以直接返回user即可
		return user;
	}
}
 
package com.spring.security.service.impl;

import java.util.Collection;
import java.util.Iterator;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;

import com.spring.security.service.CustomAccessDecisionManager;

/**
 * AccessdecisionManager在Spring security中是很重要的。
 * 
 * 在验证部分简略提过了,所有的Authentication实现需要保存在一个GrantedAuthority对象数组中。 这就是赋予给主体的权限。
 * GrantedAuthority对象通过AuthenticationManager 保存到
 * Authentication对象里,然后从AccessDecisionManager读出来,进行授权判断。
 * 
 * Spring Security提供了一些拦截器,来控制对安全对象的访问权限,例如方法调用或web请求。
 * 一个是否允许执行调用的预调用决定,是由AccessDecisionManager实现的。 这个 AccessDecisionManager
 * 被AbstractSecurityInterceptor调用, 它用来作最终访问控制的决定。
 * 这个AccessDecisionManager接口包含三个方法:
 * 
 * void decide(Authentication authentication, Object secureObject,
 * List<ConfigAttributeDefinition> config) throws AccessDeniedException; boolean
 * supports(ConfigAttribute attribute); boolean supports(Class clazz);
 * 
 * 从第一个方法可以看出来,AccessDecisionManager使用方法参数传递所有信息,这好像在认证评估时进行决定。
 * 特别是,在真实的安全方法期望调用的时候,传递安全Object启用那些参数。 比如,让我们假设安全对象是一个MethodInvocation。
 * 很容易为任何Customer参数查询MethodInvocation,
 * 然后在AccessDecisionManager里实现一些有序的安全逻辑,来确认主体是否允许在那个客户上操作。
 * 如果访问被拒绝,实现将抛出一个AccessDeniedException异常。
 * 
 * 这个 supports(ConfigAttribute) 方法在启动的时候被
 * AbstractSecurityInterceptor调用,来决定AccessDecisionManager
 * 是否可以执行传递ConfigAttribute。 supports(Class)方法被安全拦截器实现调用,
 * 包含安全拦截器将显示的AccessDecisionManager支持安全对象的类型。
 */

@Service("customAccessDecisionManager")
public class CustomAccessDecisionManagerImpl implements CustomAccessDecisionManager {

	/* (non-Javadoc)
	 * @see org.springframework.security.access.AccessDecisionManager#decide(org.springframework.security.core.Authentication, java.lang.Object, java.util.Collection)
	 */
	public void decide(Authentication authentication, Object object,Collection<ConfigAttribute> configAttributes)
		throws AccessDeniedException, InsufficientAuthenticationException {

		if (configAttributes == null) {
			return;
		}

		Iterator<ConfigAttribute> ite = configAttributes.iterator();

		while (ite.hasNext()) {

			ConfigAttribute ca = ite.next();
			String needRole = ((SecurityConfig) ca).getAttribute();

			// ga 为用户所被赋予的权限。 needRole 为访问相应的资源应该具有的权限。
			for (GrantedAuthority ga : authentication.getAuthorities()) {
				if (needRole.trim().equals(ga.getAuthority().trim())) {
					return;
				}
			}
		}

		throw new AccessDeniedException("Acess Denied");
	}

	/* (non-Javadoc)
	 * @see org.springframework.security.access.AccessDecisionManager#supports(org.springframework.security.access.ConfigAttribute)
	 */
	public boolean supports(ConfigAttribute attribute) {

		return true;
	}

	/* (non-Javadoc)
	 * @see org.springframework.security.access.AccessDecisionManager#supports(java.lang.Class)
	 */
	public boolean supports(Class<?> clazz) {

		return true;
	}
}
 
package com.spring.security.service.impl;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;

import com.spring.security.service.CustomFilterSecurityInterceptor;

/** */
/**
 * 该过滤器的主要作用就是通过spring著名的IoC生成securityMetadataSource。
 * securityMetadataSource相当于本包中自定义的MyInvocationSecurityMetadataSourceService。
 * 该MyInvocationSecurityMetadataSourceService的作用提从数据库提取权限和资源,装配到HashMap中,
 * 供Spring Security使用,用于权限校验。
 * 
 */

@Service("customFilterSecurityInterceptor")
public class CustomFilterSecurityInterceptorImpl extends AbstractSecurityInterceptor implements CustomFilterSecurityInterceptor {

	private FilterInvocationSecurityMetadataSource securityMetadataSource;
	
	public void setSecurityMetadataSource(
			FilterInvocationSecurityMetadataSource securityMetadataSource) {
		this.securityMetadataSource = securityMetadataSource;
	}


	public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {

		FilterInvocation fi = new FilterInvocation(request, response, chain);
		invoke(fi);
	}

	public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
		
		return this.securityMetadataSource;
	}

	public Class<? extends Object> getSecureObjectClass() {
		
		return FilterInvocation.class;
	}

	public void invoke(FilterInvocation fi) throws IOException,ServletException {

		InterceptorStatusToken token = super.beforeInvocation(fi);

		try {
			fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
		} finally {
			super.afterInvocation(token, null);
		}

	}

	@Override
	public SecurityMetadataSource obtainSecurityMetadataSource() {
		return this.securityMetadataSource;
	}
	
	public void destroy() {
		
	}

	public void init(FilterConfig filterconfig) throws ServletException {

	}
}
 
package com.spring.security.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;

import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.util.AntPathRequestMatcher;
import org.springframework.stereotype.Service;

import com.spring.security.dao.ResourceDao;
import com.spring.security.domain.Resource;
import com.spring.security.domain.Role;
import com.spring.security.service.CustomInvocationSecurityMetadataSource;

@Service("customInvocationSecurityMetadataSource")
public class CustomInvocationSecurityMetadataSourceImpl implements CustomInvocationSecurityMetadataSource {

	@javax.annotation.Resource
	private ResourceDao resourceDao;

	private AntPathRequestMatcher pathMatcher;

	private HashMap<String, Collection<ConfigAttribute>> resourceMap = null;

	/**
	 * 自定义方法,这个类放入到Spring容器后,
	 * 指定init为初始化方法,从数据库中读取资源
	 * 
	 */
	@PostConstruct
	public void init(){
		
		this.resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
		for (Resource item : resourceDao.getAllResource()) {
			resourceMap.put(item.getResource_string(), listToCollection(item.getRoles()));
		}
	}

	@Override
	public Collection<ConfigAttribute> getAllConfigAttributes() {
		
		Set<ConfigAttribute> allAttributes = new HashSet<ConfigAttribute>();
		for (Map.Entry<String, Collection<ConfigAttribute>> entry : resourceMap.entrySet()) {
			allAttributes.addAll(entry.getValue());
		}
		
		return allAttributes;
	}

	@Override
	public Collection<ConfigAttribute> getAttributes(Object object)throws IllegalArgumentException {
		
		HttpServletRequest request = ((FilterInvocation) object).getRequest();
		System.out.println("requestUrl is " + request.getRequestURI());
		
		if (resourceMap == null) {
			this.loadAllResourcesAndAuthorities();
		}
		Iterator<String> it = resourceMap.keySet().iterator();
		
		while (it.hasNext()) {
			String resURL = it.next();
			pathMatcher = new AntPathRequestMatcher(resURL);
			if (pathMatcher.matches(request)) {
				Collection<ConfigAttribute> returnCollection = resourceMap.get(resURL);
				
				return returnCollection;
			}
		}
		
		return null;
	}

	@Override
	public boolean supports(Class<?> arg0) {
		// TODO Auto-generated method stub
		return true;
	}

	
	/**
	 * 自定义方法,将List<Role>集合转换为框架需要的Collection<ConfigAttribute>集合
	 * 
	 * @param roles
	 * @return
	 */
	private Collection<ConfigAttribute> listToCollection(List<Role> roles) {
		
		List<ConfigAttribute> list = new ArrayList<ConfigAttribute>();
		
		for (Role role : roles) {
			list.add(new SecurityConfig(role.getRole_name()));
		}
		
		return list;
	}
	
	/**
	 * 加载所有资源与权限的关系
	 */
	private void loadAllResourcesAndAuthorities() {
		
		if (resourceMap == null) {
			resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
		}
		
		List<Resource> resources = this.resourceDao.getAllResource();
		for (Resource resource : resources) {
			resourceMap.put(resource.getResource_string(),listToCollection(resource.getRoles()));
		}
	}
}
 

3、定义用户,角色,资源的类

 

package com.spring.security.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * Resources
 */

public class Resource implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private Integer id;
	private String resource_name;
	private String resource_type;
	private String resource_string;
	private String resource_enabled;
	private String resource_desc;
	private List<Role> roles = new ArrayList<Role>();

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getResource_name() {
		return resource_name;
	}

	public void setResource_name(String resource_name) {
		this.resource_name = resource_name;
	}

	public String getResource_type() {
		return resource_type;
	}

	public void setResource_type(String resource_type) {
		this.resource_type = resource_type;
	}

	public String getResource_string() {
		return resource_string;
	}

	public void setResource_string(String resource_string) {
		this.resource_string = resource_string;
	}

	public String getResource_enabled() {
		return resource_enabled;
	}

	public void setResource_enabled(String resource_enabled) {
		this.resource_enabled = resource_enabled;
	}

	public String getResource_desc() {
		return resource_desc;
	}

	public void setResource_desc(String resource_desc) {
		this.resource_desc = resource_desc;
	}

	public List<Role> getRoles() {
		return roles;
	}

	public void setRoles(List<Role> roles) {
		this.roles = roles;
	}
}
 
package com.spring.security.domain;

import java.io.Serializable;

/**
 * Roles.
 */

public class Role implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private Integer id;
	private String role_name;
	private Integer role_enabled;
	private String role_desc;

	public Role() {
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getRole_name() {
		return role_name;
	}

	public void setRole_name(String role_name) {
		this.role_name = role_name;
	}

	public Integer getRole_enabled() {
		return role_enabled;
	}

	public void setRole_enabled(Integer role_enabled) {
		this.role_enabled = role_enabled;
	}

	public String getRole_desc() {
		return role_desc;
	}

	public void setRole_desc(String role_desc) {
		this.role_desc = role_desc;
	}
}
 
package com.spring.security.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

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

public class User implements UserDetails, Serializable {

	private static final long serialVersionUID = 1L;
	
	private Integer id;
	private String user_account;
	private Integer user_enabled;
	private String user_password;
	private String user_desc;
	private List<Role> roles = new ArrayList<Role>();

	public User() {
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUser_account() {
		return user_account;
	}

	public void setUser_account(String user_account) {
		this.user_account = user_account;
	}

	public Integer getUser_enabled() {
		return user_enabled;
	}

	public void setUser_enabled(Integer user_enabled) {
		this.user_enabled = user_enabled;
	}

	public String getUser_password() {
		return user_password;
	}

	public void setUser_password(String user_password) {
		this.user_password = user_password;
	}

	public String getUser_desc() {
		return user_desc;
	}

	public void setUser_desc(String user_desc) {
		this.user_desc = user_desc;
	}

	public List<Role> getRoles() {
		return roles;
	}

	public void setRoles(List<Role> roles) {
		this.roles = roles;
	}

	/*
	 * 获取用户权限集合,权限使用GrantedAuthority接口表示,框架中有它的实现类
	 * GrantedAuthorityImpl,只需要把角色的名称放入即可 (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.security.core.userdetails.UserDetails#getAuthorities
	 * ()
	 */
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
		for (Role role : roles) {
			list.add(new SimpleGrantedAuthority(role.getRole_name()));
		}

		return list;
	}

	/*
	 * 获取用户名 (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.security.core.userdetails.UserDetails#getUsername()
	 */
	@Override
	public String getUsername() {
		// TODO Auto-generated method stub
		return this.user_account;
	}

	/*
	 * 用户密码 (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.security.core.userdetails.UserDetails#getPassword()
	 */
	@Override
	public String getPassword() {
		// TODO Auto-generated method stub
		return this.user_password;
	}

	/*
	 * 直接返回true,表示没有过期 (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.security.core.userdetails.UserDetails#isAccountNonExpired
	 * ()
	 */
	@Override
	public boolean isAccountNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	/*
	 * 直接返回true,表示没有锁定 (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.security.core.userdetails.UserDetails#isAccountNonLocked
	 * ()
	 */
	@Override
	public boolean isAccountNonLocked() {
		// TODO Auto-generated method stub
		return true;
	}

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

	/*
	 * 是否禁用 (non-Javadoc)
	 * 
	 * @see
	 * org.springframework.security.core.userdetails.UserDetails#isEnabled()
	 */
	@Override
	public boolean isEnabled() {
		// TODO Auto-generated method stub
		return true;
	}
}

 4 用户,资源,角色DAo类的实现

package com.spring.security.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.spring.security.dao.UserDao;
import com.spring.security.dao.support.SimpleDaoSupport;
import com.spring.security.domain.Role;
import com.spring.security.domain.User;

@Repository("userDao")
public class UserDaoImpl extends SimpleDaoSupport implements UserDao {

	@Override
	public User findUserByName(String userName) {

		String sql = "SELECT id,user_account,user_enabled,user_password,user_desc FROM pub_users where user_account=?";
		
		return this.getSimpleJdbcTemplate().queryForObject(sql,
				new UserMapper(), userName);
	}

	/**
	 * 获取User对象的role列表
	 * 
	 * @param userID
	 * @return RoleList
	 */
	public List<Role> getRolesByUserID(String userName) {

		String sql = "SELECT r.id,r.role_name,r.role_enabled,r.role_desc FROM pub_users u,pub_roles r,pub_users_roles ur "
				+ "WHERE u.id=ur.user_id AND r.id=ur.role_id AND u.user_account=?";

		return this.getSimpleJdbcTemplate().query(sql,
				BeanPropertyRowMapper.newInstance(Role.class), userName);
	}

	/**
	 * 定义UserMapper
	 */
	protected class UserMapper implements RowMapper<User> {

		public User mapRow(ResultSet rs, int rowNum) throws SQLException {
			User user = new User();
			user.setId(rs.getInt("id"));
			user.setUser_account(rs.getString("user_account"));
			user.setUser_password(rs.getString("user_password"));
			user.setUser_enabled(rs.getInt("user_enabled"));
			user.setUser_desc(rs.getString("user_desc"));

			// 调用上面的方法获取用户所有的权限
			user.setRoles(getRolesByUserID(rs.getString("user_account")));

			return user;
		}
	}
}
 
package com.spring.security.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.spring.security.dao.ResourceDao;
import com.spring.security.dao.support.SimpleDaoSupport;
import com.spring.security.domain.Resource;
import com.spring.security.domain.Role;

@Repository("resourceDao")
public class ResourceDaoImpl extends SimpleDaoSupport implements ResourceDao {

	@Override
	public List<Resource> getAllResource() {

		List<Resource> list = null;
		String sql = "SELECT * from pub_resources";
		list = this.getSimpleJdbcTemplate().query(sql, new RowMapper<Resource>() {
			public Resource mapRow(ResultSet rs, int arg1) throws SQLException {
				Resource resource = new Resource();
				resource.setId(rs.getInt("id"));
				resource.setResource_name(rs.getString("resource_name"));
				resource.setResource_type(rs.getString("resource_type"));
				resource.setResource_string(rs.getString("resource_string"));
				resource.setResource_enabled(rs.getString("resource_enabled"));
				resource.setResource_desc(rs.getString("resource_desc"));
				resource.setRoles(getRoleByResourceId(resource.getId()));
				
				return resource;
			}
		});
		
		return list;
	}
	
	private List<Role> getRoleByResourceId(int id) {
		
		String sql = "SELECT r.id,r.role_name,r.role_enabled,r.role_desc FROM pub_roles r,pub_roles_resources rr WHERE rr.role_id=r.id AND rr.resource_id=?";
		return this.getSimpleJdbcTemplate().query(sql, new RowMapper<Role>() {
			public Role mapRow(ResultSet rs, int arg1) throws SQLException {
				Role role = new Role();
				role.setId(rs.getInt("id"));
				role.setRole_name(rs.getString("role_name"));
				role.setRole_enabled(rs.getInt("role_enabled"));
				role.setRole_desc(rs.getString("role_desc"));
				
				return role;
			}
		}, new Object[] { id });
	}
}
 

5 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.1.xsd">

	<global-method-security pre-post-annotations="enabled" />

	<!--对登录页面不进行拦截,在页面后面加*表示,该页面后面可能会带一些参数 -->
	<http pattern="/login.jsp*" security="none" />
	<http pattern="/common/**" security="none" />
	<http pattern="/js/**" security="none" />

	<!-- 保护应用程序配置一些列的权限问题,当没有权限403返回页面为403.jsp -->
	<http auto-config="true" access-denied-page="/common/403.jsp" use-expressions="true">
		<!-- login-page: 指定登录页面,并指定默认的target访问地址index.jsp -->
		<form-login login-page="/login.jsp" default-target-url='/index.jsp' always-use-default-target='true' />
		<!-- 配置用户退出的默认返回页面 -->
		<logout logout-success-url="/login.jsp" />
		<!-- 会话管理配置 ,设置最多登录一次,二次登录会让第一次登录失效,
		 则设置error-if-maximum-exceeded为false,要求第一次有效设置为true -->
		<session-management invalid-session-url="/common/timeout.jsp">
			<concurrency-control max-sessions="1" error-if-maximum-exceeded="false" />
		</session-management>

		<!-- 将自己的过滤器加入到过滤器链中, 放在FILTER_SECURITY_INTERCEPTOR之前 -->
		<custom-filter ref="customFilterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" />
	</http>

	<!-- 配置自己的拦截器 -->
	<beans:bean id="customFilterSecurityInterceptor"
		class="com.spring.security.service.impl.CustomFilterSecurityInterceptorImpl">
		<beans:property name="authenticationManager" ref="autheticationManager"/>
		<beans:property name="accessDecisionManager" ref="customAccessDecisionManager" />
		<!-- resourceService在applicationContext.xml中定义 -->
		<beans:property name="securityMetadataSource" ref="customInvocationSecurityMetadataSource" />
	</beans:bean>

	<!--配置认证管理器 -->
	<authentication-manager alias="autheticationManager">
		<!-- 使用自定义UserDetailsService -->
		<authentication-provider user-service-ref="customUserDetailsService">
			<password-encoder hash="md5"/>
		</authentication-provider>
	</authentication-manager>
	
	<beans:bean id="webPrivilegeEvaluator" class="org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator"> 
    	<beans:constructor-arg ref="customFilterSecurityInterceptor"/>
    </beans:bean>
    
   <!-- Jcaptcha相关的配置 -->   
    <beans:bean id="captchaService"  class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService">   
        <beans:property name="captchaEngine">   
            <beans:bean class="com.spring.security.jcaptcha.GMailEngine" />   
        </beans:property>   
        <!-- 默认生成的图片180秒过期 , 可另行设置 -->    
        <beans:property name="minGuarantedStorageDelayInSeconds" value="180" />   
    </beans:bean>
    
</beans:beans>

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">
	<display-name>springSecurityIII</display-name>
	<context-param>
		<param-name>log4jConfigLocation</param-name>
		<param-value>classpath:log4j.xml</param-value>
	</context-param>
	<context-param>
		<param-name>log4jRefreshInterval</param-name>
		<param-value>60000</param-value>
	</context-param>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
	</listener>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<listener>
		<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
	</listener>
	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<session-config>
		<session-timeout>30</session-timeout>
	</session-config>
	
	<!-- JCaptcha`s filter -->
	<filter>
		<filter-name>jcaptchaFilter</filter-name>
		<filter-class>com.spring.security.jcaptcha.JCaptchaFilter</filter-class>
		<init-param>
			<param-name>failureUrl</param-name>
			<param-value>/login.jsp</param-value>
		</init-param>
	</filter>
	
	<!-- jcaptcha图片生成URL. -->
	<filter-mapping>
		<filter-name>jcaptchaFilter</filter-name>
		<url-pattern>/jcaptcha.jpg</url-pattern>
	</filter-mapping>
	
	<!-- jcaptcha登录表单处理URL. 必须放在springSecurityFilter的filter-mapping定义之前 -->
	<filter-mapping>
		<filter-name>jcaptchaFilter</filter-name>
		<url-pattern>/j_spring_security_check</url-pattern>
	</filter-mapping>
	
	<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>
	
	<listener>
		<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
	</listener>

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>
 

 

 

6、其他页面保持不变,进行访问页面如下:

 



 

 admin用户点击admin页面



 切换user用户登入页面进入

 



 点击admin页面,用户访问被拒绝


总结: 这种方法虽然将用户、角色、资源存放到数据库中,但spring security 中<sec:authorize url> tag 的隐藏功能消失,这需要自己去定义类似标签去自行控制。

 

要想在真正在企业中做到很好的控制,其设计会更复杂,下面是基于RBAC设计的数据库

 


  • 大小: 19.3 KB
  • 大小: 69.5 KB
  • 大小: 10.2 KB
  • 大小: 70.1 KB
  • 大小: 17.7 KB
  • 大小: 142.5 KB
分享到:
评论
9 楼 hmcheng 2013-08-15  
能否发源码邮箱hmcheng001@126.COM,谢谢!
8 楼 FUCAIHE 2013-05-28  
org.springframework.security.web.util.AntPathRequestMatcher
这个包怎么找不到啊
7 楼 Johnny_L 2012-09-14  
楼主麻烦发下完整的源码到我邮箱好吗?我也是弄了好多天了!280237032@qq.com谢谢
6 楼 jiang_xiaohan 2012-09-11  
楼主源码能发我么,纠结好多天了,还是没调好,我邮箱1307126091@qq.com
5 楼 bingfengfzl 2012-07-27  
求源码,这位大哥你写得实在是太好了,不知是否可以给小弟一份源码?bingfengfzl@163.com
4 楼 efanhome 2012-04-12  
楼主,求源码。谢谢。efanhome@qq.com 对于初学者来说,磕磕碰碰的地方太多了。
3 楼 topkaiser 2012-04-09  
收益良多,多谢楼主,有过有可能的话能否把源码给我发一份,不胜感激,我的邮箱是:329964869@qq.com。再次感谢!
2 楼 wangwangli6 2012-03-22  
almtalmt 写道
楼主能否把其余的源码附上,谢谢。

1 楼 almtalmt 2011-11-13  
楼主能否把其余的源码附上,谢谢。

相关推荐

    spring security进级篇 V 自定义标签控制显示

    这篇"Spring Security进阶篇 V 自定义标签控制显示"的博客文章显然深入探讨了如何在Spring Security中实现自定义的安全控制,以便更好地管理和展示应用内容。在本文中,我们将详细解析这个主题,并与"JSP自定义标签...

    springsecurity3x快速构建企业级安全

    本篇将深入探讨Spring Security 3.x的核心概念和主要功能,帮助你快速理解和应用到企业级项目中。 1. **核心概念** - **认证(Authentication)**:Spring Security提供了多种认证机制,如基于表单的身份验证、...

    spring security3 开发手册

    Spring Security 3作为该框架的一个版本,提供了丰富的安全性配置选项,涵盖了从基础的认证和授权到复杂的单点登录和方法保护等各个方面。 ### 基础篇 #### Hello World示例 Spring Security的入门通常以一个简单...

    spring-security3 入门篇

    本入门篇将介绍Spring Security的基础知识,包括其核心概念、配置以及如何在实际项目中使用。 1. **核心概念** - **Authentication(认证)**: 用户身份验证是Spring Security的基础,它确认用户的身份是否合法。...

    spring security 3.1学习资料 及 附件下载

    Spring Security是Java平台上的一款强大且高度可定制的安全框架,广泛应用于企业级Web应用的安全管理。本篇文章将围绕"Spring Security 3.1"这一主题,深入探讨其核心概念、功能特性以及实际应用。 一、Spring ...

    Spring Security详细介绍及使用含完整代码(值得珍藏)

    通过本篇文章的学习,你不仅了解了Spring Security的基本原理和使用方法,还学习了如何在Spring Boot项目中集成和配置Spring Security。这对于开发安全稳定的企业应用来说至关重要。希望你能通过实践进一步掌握...

    Spring Security tutorial 学习笔记(一)

    在 `SpringSecurityTest01` 这个压缩包文件中,你可能找到了一个示例项目,它可能包含了配置类、控制器、视图和测试用例。通过分析这些代码,你可以更深入地理解如何在实际项目中应用 Spring Security。 总之,...

    SpringSecurity3框架

    本篇将深入探讨Spring Security 3的核心概念和主要特性。 1. **核心概念** - **Authentication**(认证):确认用户身份的过程,Spring Security提供了多种认证机制,如基于表单的登录、基于HTTP基本认证或OAuth2...

    Spring Security 3系列文章——入门篇(一)

    **Spring Security 3 系列文章——入门篇(一)** Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,广泛应用于Java企业级应用和Spring Boot项目中。本篇将作为Spring Security 3的入门介绍,帮助...

    Spring-Security安全权限管理手册

    **基础篇**主要介绍如何配置和使用Spring Security。本节将详细介绍Spring Security的基本配置过程,以及如何通过Maven管理项目的依赖。 - **使用Maven管理依赖**:由于Spring框架本身体积较大(Spring.jar就有2M多...

    spring-security-3.1.0.RC3

    《Spring Security 3.1.0.RC3:企业级安全框架详解》 Spring Security是Java平台上广泛使用的安全框架,其3.1.0.RC3版本为开发者提供了强大而灵活的安全控制,使得构建安全的Web应用变得简单易行。本篇文章将深入...

    spring security的学习-3. 自定义数据库表结构.doc

    在本篇关于“Spring Security的学习-3. 自定义数据库表结构”的文档中,我们将探讨如何根据企业特定的需求来定制Spring Security的数据库表结构,并且如何初始化数据以及获取自定义的用户权限信息。Spring Security...

    Spring Security权限管理开发手册

    而“保护Web篇”则更深入地探讨如何利用Spring Security来保护Web应用程序的安全。 - **意见反馈与相关信息:** - 鼓励读者提出反馈意见和建议,以便不断完善和改进手册内容。 #### 二、基础篇 - **第1章:一个...

    spring security 3权限管理代码

    本篇文章将深入探讨Spring Security 3中的核心概念和实现权限管理的相关知识点。 1. **身份验证(Authentication)**:Spring Security通过`Authentication`接口处理用户的身份验证。当用户尝试访问受保护的资源时...

    Spring Security3 配置使用

    这篇博客将深入探讨Spring Security 3的配置和使用方法。 1. **核心组件** - **SecurityContextHolder**: 它是Spring Security的核心组件,存储当前线程的安全上下文,用于获取认证和授权信息。 - **...

    Spring Security3技术手册

    ### Spring Security3技术手册知识点概览 #### 一、基础篇 **1. 一个简单的Hello World** - **1.1 配置过滤器** - Spring Security通过一系列的过滤器来实现对Web应用程序的安全控制。了解如何配置这些过滤器是...

Global site tag (gtag.js) - Google Analytics