spring security 3.1中基于数据库自定义验证授权功能实现

一、数据库表有5个:users、roles、perms、users_roles、roles_perms。

大家一看就知道这5个表是做什么用的了。

脚本如下:

/*
Navicat MySQL Data Transfer

Source Server         : localhost_3306
Source Server Version : 50154
Source Host           : localhost:3306
Source Database       : mis2013

Target Server Type    : MYSQL
Target Server Version : 50154
File Encoding         : 65001

Date: 2013-07-10 01:08:05
*/

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `perms`
-- ----------------------------
DROP TABLE IF EXISTS `perms`;
CREATE TABLE `perms` (
  `id` varchar(36) NOT NULL,
  `permname` varchar(50) NOT NULL,
  `permtype` varchar(15) DEFAULT 'jsp',
  `permstr` varchar(255) DEFAULT NULL,
  `priority` int(11) DEFAULT '0',
  `description` varchar(255) DEFAULT '鏃?,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of perms
-- ----------------------------
INSERT INTO `perms` VALUES ('perm1', '绠$悊鐩綍', 'dir', '/adroot/**', '1', '鏃?);
INSERT INTO `perms` VALUES ('perm2', '鐧诲綍椤甸潰', 'jsp', '/login.jsp', '0', '鏃?);
INSERT INTO `perms` VALUES ('perm3', '娉ㄥ唽椤甸潰', 'jsp', '/register.jsp', '0', '鏃?);
INSERT INTO `perms` VALUES ('perm4', '绯荤粺涓婚〉', 'jsp', '/index.jsp', '0', '鏃?);

-- ----------------------------
-- Table structure for `roles`
-- ----------------------------
DROP TABLE IF EXISTS `roles`;
CREATE TABLE `roles` (
  `id` varchar(36) NOT NULL,
  `description` varchar(255) DEFAULT NULL,
  `rolename` varchar(50) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of roles
-- ----------------------------
INSERT INTO `roles` VALUES ('ROLE_ADMIN', '绠$悊瑙掕壊', 'ROLE_ADMIN');
INSERT INTO `roles` VALUES ('ROLE_ANONYMOUS', '璁垮瑙掕壊', 'ROLE_ANONYMOUS');
INSERT INTO `roles` VALUES ('ROLE_USER', '鐢ㄦ埛瑙掕壊', 'ROLE_USER');

-- ----------------------------
-- Table structure for `roles_perms`
-- ----------------------------
DROP TABLE IF EXISTS `roles_perms`;
CREATE TABLE `roles_perms` (
  `roles_id` varchar(36) NOT NULL,
  `perms_id` varchar(36) NOT NULL,
  PRIMARY KEY (`roles_id`,`perms_id`),
  KEY `FK2E481B81CADB7376` (`perms_id`),
  KEY `FK2E481B81A0EF5B82` (`roles_id`),
  CONSTRAINT `FK2E481B81A0EF5B82` FOREIGN KEY (`roles_id`) REFERENCES `roles` (`id`),
  CONSTRAINT `FK2E481B81CADB7376` FOREIGN KEY (`perms_id`) REFERENCES `perms` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of roles_perms
-- ----------------------------
INSERT INTO `roles_perms` VALUES ('ROLE_ADMIN', 'perm1');
INSERT INTO `roles_perms` VALUES ('ROLE_ANONYMOUS', 'perm2');
INSERT INTO `roles_perms` VALUES ('ROLE_USER', 'perm2');
INSERT INTO `roles_perms` VALUES ('ROLE_ANONYMOUS', 'perm3');
INSERT INTO `roles_perms` VALUES ('ROLE_USER', 'perm3');
INSERT INTO `roles_perms` VALUES ('ROLE_USER', 'perm4');

-- ----------------------------
-- Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` varchar(36) NOT NULL,
  `username` varchar(50) NOT NULL,
  `password` varchar(32) DEFAULT NULL,
  `enabled` tinyint(4) DEFAULT '1',
  `description` varchar(255) DEFAULT '鏃?,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('admin', 'admin', 'admin', '1', null);
INSERT INTO `users` VALUES ('user', 'user', 'user', '1', null);

-- ----------------------------
-- Table structure for `users_roles`
-- ----------------------------
DROP TABLE IF EXISTS `users_roles`;
CREATE TABLE `users_roles` (
  `users_id` varchar(36) NOT NULL,
  `roles_id` varchar(36) NOT NULL,
  PRIMARY KEY (`users_id`,`roles_id`),
  KEY `FKF6CCD9C6A0EF5B82` (`roles_id`),
  KEY `FKF6CCD9C6A0F27FAC` (`users_id`),
  CONSTRAINT `FKF6CCD9C6A0EF5B82` FOREIGN KEY (`roles_id`) REFERENCES `roles` (`id`),
  CONSTRAINT `FKF6CCD9C6A0F27FAC` FOREIGN KEY (`users_id`) REFERENCES `users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of users_roles
-- ----------------------------
INSERT INTO `users_roles` VALUES ('admin', 'ROLE_ADMIN');
INSERT INTO `users_roles` VALUES ('admin', 'ROLE_ANONYMOUS');
INSERT INTO `users_roles` VALUES ('user', 'ROLE_ANONYMOUS');
INSERT INTO `users_roles` VALUES ('admin', 'ROLE_USER');
INSERT INTO `users_roles` VALUES ('user', 'ROLE_USER');

二、域模型为:User、Role、Perm。

User和Role、Role和Perm都是多对多的关系。代码如下:

package pw.cmos.user.model;

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

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Proxy;

@Entity
@Proxy(lazy = false)  
@Table(name = "users", catalog = "mis2013")
public class User {
	private String id;
	private String username;
	private String password;
	private boolean enabled;
	private String description;
	private Set<Role> roles = new HashSet<Role>();

	@GenericGenerator(name = "generator", strategy = "uuid.hex")
	@Id
	@GeneratedValue(generator = "generator")
	@Column(name = "id", unique = true, nullable = false, length = 36)
	public String getId() {
		return id;
	}

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

	@Column(name = "username", nullable = false, length = 50)
	public String getUsername() {
		return username;
	}

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

	@Column(name = "password", length = 32)
	public String getPassword() {
		return password;
	}

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

	@Column(name = "enabled")
	public boolean isEnabled() {
		return enabled;
	}

	public void setEnabled(boolean enabled) {
		this.enabled = enabled;
	}

	@Column(name = "description", length = 255)
	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	@ManyToMany(targetEntity = Role.class, fetch = FetchType.EAGER)
	@JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "users_id"), inverseJoinColumns = @JoinColumn(name = "roles_id"))
	public Set<Role> getRoles() {
		return roles;
	}

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


 

package pw.cmos.user.model;

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

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "roles", catalog = "mis2013")
public class Role {
	private String id;
	private String rolename;
	private String description;
	private Set<User> users = new HashSet<User>();
	private Set<Perm> perms = new HashSet<Perm>();

	@GenericGenerator(name = "generator", strategy = "uuid.hex")
	@Id
	@GeneratedValue(generator = "generator")
	@Column(name = "id", unique = true, nullable = false, length = 36)
	public String getId() {
		return id;
	}

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

	@Column(name = "rolename", nullable = false, length = 50)
	public String getRolename() {
		return rolename;
	}

	public void setRolename(String rolename) {
		this.rolename = rolename;
	}

	@Column(name = "description", length = 255)
	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	@ManyToMany(mappedBy = "roles")
	public Set<User> getUsers() {
		return users;
	}

	public void setUsers(Set<User> users) {
		this.users = users;
	}

	@ManyToMany(targetEntity = Perm.class, fetch = FetchType.EAGER)
	@JoinTable(name = "roles_perms", joinColumns = @JoinColumn(name = "roles_id"), inverseJoinColumns = @JoinColumn(name = "perms_id"))
	public Set<Perm> getPerms() {
		return perms;
	}

	public void setPerms(Set<Perm> perms) {
		this.perms = perms;
	}
}


package pw.cmos.user.model;

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

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "perms", catalog = "mis2013")
public class Perm {
	private String id;
	private String permname;
	private String permtype;
	private String permstr;
	private Integer priority;
	private String description;
	private Set<Role> roles = new HashSet<Role>();

	@Id
	@GeneratedValue(generator = "generator")
	@GenericGenerator(name = "generator", strategy = "uuid.hex")
	@Column(name = "id", unique = true, nullable = false, length = 36)
	public String getId() {
		return id;
	}

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

	@Column(name = "permname", nullable = false, length = 50)
	public String getPermname() {
		return permname;
	}

	public void setPermname(String permname) {
		this.permname = permname;
	}

	@Column(name = "permtype", length = 15)
	public String getPermtype() {
		return permtype;
	}

	public void setPermtype(String permtype) {
		this.permtype = permtype;
	}

	@Column(name = "permstr", length = 255)
	public String getPermstr() {
		return permstr;
	}

	public void setPermstr(String permstr) {
		this.permstr = permstr;
	}

	@Column(name = "priority")
	public Integer getPriority() {
		return priority;
	}

	public void setPriority(Integer priority) {
		this.priority = priority;
	}

	@Column(name = "description", length = 255)
	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	@ManyToMany(mappedBy = "perms", targetEntity = Role.class, fetch = FetchType.EAGER)
	public Set<Role> getRoles() {
		return roles;
	}

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

}


三、域对象的DAO类:UserDAO、RoleDAO、PermDAO,为方便session的获取,他们都继承自BaseDAO,该类代码如下:

package pw.cmos.user.dao;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

public class BaseDAO {
	@Autowired
	private SessionFactory sessionFactory;

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	
	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}
}

这里通过注解方式注入sessionFactory,该工厂类在xml中已经配置,请参看后面的Context.xml代码。

为了减少类之间的耦合,一般考虑用接口来实现类与类的调用。DAO都实现了相应的接口,比如UserDAO类实现IUserDAO接口。

package pw.cmos.user.dao;

import java.util.List;
import pw.cmos.user.model.User;

public interface IUserDAO {

	public abstract void save(User user);

	public abstract void delete(User user);

	public abstract User findUserById(final String id);

	public abstract User findUserByUsername(final String username);

	public abstract List findByProperty(String propertyName, Object value);

	public abstract User getUserByName(String username);

	public abstract List<String> loadUserAuthoritiesByName(String username);

}


 

package pw.cmos.user.dao;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.stereotype.Repository;

import pw.cmos.user.model.Role;
import pw.cmos.user.model.User;

@Repository
public class UserDAO extends BaseDAO implements IUserDAO {

	@Override
	public void save(User user) {
	}

	@Override
	public void delete(User user) {
		// TODO Auto-generated method stub

	}

	@Override
	public User findUserById(String id) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public User findUserByUsername(String username) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List findByProperty(String propertyName, Object value) {
		// TODO Auto-generated method stub
		return null;
	}

	public User getUserByName(String username) {
		Session s = getSession();
		Query query = s.createQuery("from User as u where u.username = ?");
		query.setString(0, username);
		User user = (User) query.uniqueResult();
		return user;
	}

	public List<String> loadUserAuthoritiesByName(String username) {
		User user = this.getUserByName(username);
		if (user != null) {
			Set<Role> roles = user.getRoles();
			List<String> auth = new ArrayList<String>();
			Iterator<Role> it = roles.iterator();
			while (it.hasNext()) {
				auth.add(((Role) it.next()).getRolename());
			}
			return auth;
		} else {
			return null;
		}
	}
}

因只谈谈spring security 的自定义实现,所以DAO类其它方法都没有具体去实现,这里仅用到两个方法:getUserByName和loadUserAuthoritiesByName。这两个方法在后面的认证中需要用到,他们主要用于根据用户名来获得认证所需的角色名,返回角色名的字符串数组。

package pw.cmos.user.dao;

import java.util.List;

import pw.cmos.user.model.Perm;

public interface IPermDAO {

	public abstract void save(Perm perm);

	public abstract void delete(Perm perm);

	public abstract Perm findPermById(final String id);

	public abstract Perm findPermByPermname(final String permname);

	public abstract List<Perm> findPermByUri(final String requestUri);

	public abstract List findByProperty(String propertyName, Object value);
}
package pw.cmos.user.dao;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.stereotype.Repository;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import pw.cmos.user.model.Perm;

@Repository
public class PermDAO extends BaseDAO implements IPermDAO {

	@Override
	public void save(Perm perm) {
		// TODO Auto-generated method stub

	}

	@Override
	public void delete(Perm perm) {
		// TODO Auto-generated method stub

	}

	@Override
	public Perm findPermById(String id) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Perm findPermByPermname(String permname) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<Perm> findPermByUri(String requestUri) {
		Session s = getSession();
		Query query = s.createQuery("from Perm");
		List<Perm> permlist = query.list();
		List<Perm> perms = new ArrayList<Perm>();
		for (Perm perm : permlist) {
			if (urlMatcher(perm.getPermstr(), requestUri))
				perms.add(perm);
		}
		return perms;
	}

	private boolean urlMatcher(String permstr, String requestUri) {
		boolean isMatcher = false;
		PathMatcher matcher = new AntPathMatcher();
		isMatcher = matcher.match(permstr, requestUri);
		return isMatcher;
	}

	@Override
	public List findByProperty(String propertyName, Object value) {
		// TODO Auto-generated method stub
		return null;
	}

}

PermDAO也仅实现了findPermByUri方法,这个方法在后面的授权中需要用到,主要用于根据用户请求的url资源地址与perm表中的授权掩码匹配,匹配通过的perm将以数组方式返回。

四、接下来,我们看看web页面的配置:

web.xml代码如下:

<?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_3_0.xsd"
	id="WebApp_ID" version="3.0">
	<display-name>mis2013</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>
	
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:Context.xml,classpath:Security.xml</param-value>
	</context-param>
	<!-- 配置spiring security -->
	<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>
	<!-- 配置spiring security结束 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener> 
	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

 

login.jsp代码如下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<%@ taglib prefix="sec"
	uri="http://www.springframework.org/security/tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>用户登陆</title>
</head>

<body>
	<a href="<s:url value='/index.jsp'/>">首页</a>
	<a href="<s:url value='/register.jsp'/>">注册</a>
	<hr size="1" />
	<s:form action="/j_spring_security_check" method="POST" namespace="/user">
		<s:fielderror></s:fielderror>
		<s:textfield key="用户" name="j_username"></s:textfield>
		<s:password key="密码" name="j_password" style="width:155px;"></s:password>
		<s:submit value="登陆系统"></s:submit>
		<s:actionerror />
	</s:form>
</body>
</html>

action必须使用/j_spring_security_check,表单name相应为:j_username,j_password。如果退出登录action为:/j_spring_security_logout


Comtext.xml代码如下:

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

	<context:component-scan base-package="pw.cmos" />

	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost:3306/mis2013">
		</property>
		<property name="username" value="root"></property>
		<property name="password" value="******"></property>
	</bean>

	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.dialect">
					org.hibernate.dialect.MySQLDialect
				</prop>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
			</props>
		</property>
		<property name="annotatedClasses">
			<list>
				<value>pw.cmos.user.model.User</value>
				<value>pw.cmos.user.model.Role</value>
				<value>pw.cmos.user.model.Perm</value>
			</list>
		</property>
	</bean>
	
	<!-- 开启注解事务 只对当前配置文件有效 -->
	<tx:annotation-driven transaction-manager="txManager" />
	<bean id="txManager"
		class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>

	<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="save*" propagation="REQUIRED" />
			<tx:method name="add*" propagation="REQUIRED" />
			<tx:method name="create*" propagation="REQUIRED" />
			<tx:method name="insert*" propagation="REQUIRED" />
			<tx:method name="*" read-only="true" />
		</tx:attributes>
	</tx:advice>

	<aop:config proxy-target-class="true">
		<aop:pointcut id="dao" expression="execution(* pw.cmos..dao.*.*(..))" />
		<aop:advisor pointcut-ref="dao" advice-ref="txAdvice" />
	</aop:config>
</beans>

这里配置了事务,因为我们在获取session时使用的是sessionFactory.getCurrentSession(),如果不配置事务的话,session是获取不到的。配置事务主要是对dao包下面的DAO方法都使用事务,这样就不需要我们在每个方法中显式使用事务api了。

五、重头戏,Security.xml的配置和自定义类的实现。

<?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">

	<http pattern="/login.jsp" security="none" />
	<http pattern="/accessDenied.jsp" security="none" />

	<http auto-config="true">
		<form-login login-page="/login.jsp"
			authentication-failure-url="/login.jsp" />
		<custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" />
	</http>

	<beans:bean id="myFilter"
		class="pw.cmos.web.security.MyFilterSecurityInterceptor">
		<beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />
		<beans:property name="authenticationManager" ref="authenticationManager" />
		<beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />
	</beans:bean>

	<authentication-manager alias="authenticationManager">
		<authentication-provider user-service-ref="myUserDetailsService">
		</authentication-provider>
	</authentication-manager>
 
	<beans:bean name="myUserDetailsService" class="pw.cmos.web.security.MyUserDetailsService">
	</beans:bean>

	<beans:bean name="myAccessDecisionManager"
		class="pw.cmos.web.security.MyAccessDecisionManager">
	</beans:bean>

	<beans:bean name="mySecurityMetadataSource"
		class="pw.cmos.web.security.MyInvocationSecurityMetadataSourceService">
	</beans:bean>

</beans:beans>

这里,我们要自定义的话,只能在spring security过滤器链中插入一个自定义的过滤器。如<custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" />,该过滤器需要三个参数accessDecisionManager、authenticationManager、securityMetadataSource。代码如下:

package pw.cmos.web.security;

import java.io.IOException;

import javax.servlet.Filter;
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;

public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor
		implements Filter {

	private FilterInvocationSecurityMetadataSource securityMetadataSource;

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		FilterInvocation fi = new FilterInvocation(request, response, chain);
		invoke(fi);

	}

	@Override
	public void destroy() {
	}

	@Override
	public Class<?> getSecureObjectClass() {
		return FilterInvocation.class;
	}

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

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

	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);
		}
	}

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

}


authenticationManager类我们主要是关心它的authentication-provider,这里我们用UserDetailsService的实现类做provider,自定义了UserDetailsService的实现,代码如下:

package pw.cmos.web.security;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import pw.cmos.user.dao.IUserDAO;
import pw.cmos.user.dao.UserDAO;
import pw.cmos.user.model.User;

public class MyUserDetailsService implements UserDetailsService {

	@Autowired
	private IUserDAO userDao;

	@Override
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException {
		Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
		User user = new User();
		try {
			user = userDao.getUserByName(username);
			List<String> authStr = userDao.loadUserAuthoritiesByName(username);
			for (String authName : authStr) {
				SimpleGrantedAuthority authority = new SimpleGrantedAuthority(
						authName);
				auths.add(authority);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return new org.springframework.security.core.userdetails.User(
				user.getUsername(), user.getPassword(), true, true, true, true,
				auths);
	}

}


 

package pw.cmos.web.security;

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

import org.springframework.security.access.AccessDecisionManager;
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;

public class MyAccessDecisionManager implements AccessDecisionManager {

	@Override
	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();
			for (GrantedAuthority ga : authentication.getAuthorities()) {
				if (needRole.trim().equals(ga.getAuthority().trim())) {
					return;
				}
			}
		}
		throw new AccessDeniedException("无权限!");

	}

	@Override
	public boolean supports(ConfigAttribute attribute) {
		return true;
	}

	@Override
	public boolean supports(Class<?> clazz) {
		return true;
	}

}

 

package pw.cmos.web.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.FilterInvocation;

import pw.cmos.user.dao.IPermDAO;
import pw.cmos.user.dao.PermDAO;
import pw.cmos.user.model.Perm;
import pw.cmos.user.model.Role;

public class MyInvocationSecurityMetadataSourceService implements
		FilterInvocationSecurityMetadataSource {

	@Autowired
	private IPermDAO permDao;

	@Override
	public Collection<ConfigAttribute> getAttributes(Object object)
			throws IllegalArgumentException {
		String url = ((FilterInvocation) object).getRequestUrl();
		int firstQuestionMarkIndex = url.indexOf("?");
		if (firstQuestionMarkIndex != -1) {
			url = url.substring(0, firstQuestionMarkIndex);
		}
		System.out.println("url:" + url);
		List<ConfigAttribute> result = new ArrayList<ConfigAttribute>();
		ConfigAttribute attribute = new SecurityConfig("ROLE_BASE");
		result.add(attribute);
		try {
			List<Perm> permList = permDao.findPermByUri(url);
			if (permList != null && permList.size() > 0) {
				for (Perm perm : permList) {
					Set<Role> roles = perm.getRoles();
					if (roles != null && roles.size() > 0) {
						for (Role role : roles) {
							ConfigAttribute conf = new SecurityConfig(
									role.getRolename());
							result.add(conf);
						}
					}
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	@Override
	public Collection<ConfigAttribute> getAllConfigAttributes() {
		// TODO Auto-generated method stub
		return null;
	}

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

}

getAttributes的功能:对请求url进行简单处理后,然后与perm表中的授权掩码匹配,查找出匹配的角色,然后以角色名new出的SecurityConfig数组,以此返回给系统进行授权。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值