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

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

/*  
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。

UserRoleRolePerm都是多对多的关系。代码如下:

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过滤器链中插入一个自定义的过滤器。如,该过滤器需要三个参数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数组,以此返回给系统进行授权。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值