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

 

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

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

脚本如下:

  1. /*  
  2. Navicat MySQL Data Transfer  
  3.   
  4. Source Server         : localhost_3306  
  5. Source Server Version : 50154  
  6. Source Host           : localhost:3306  
  7. Source Database       : mis2013  
  8.   
  9. Target Server Type    : MYSQL  
  10. Target Server Version : 50154  
  11. File Encoding         : 65001  
  12.   
  13. Date: 2013-07-10 01:08:05  
  14. */  
  15.   
  16. SET FOREIGN_KEY_CHECKS=0;  
  17. -- ----------------------------  
  18. -- Table structure for `perms`  
  19. -- ----------------------------  
  20. DROP TABLE IF EXISTS `perms`;  
  21. CREATE TABLE `perms` (  
  22.   `id` varchar(36) NOT NULL,  
  23.   `permname` varchar(50) NOT NULL,  
  24.   `permtype` varchar(15) DEFAULT 'jsp',  
  25.   `permstr` varchar(255) DEFAULT NULL,  
  26.   `priority` int(11) DEFAULT '0',  
  27.   `description` varchar(255) DEFAULT '鏃?,  
  28.   PRIMARY KEY (`id`),  
  29.   UNIQUE KEY `id` (`id`)  
  30. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
  31.   
  32. -- ----------------------------  
  33. -- Records of perms  
  34. -- ----------------------------  
  35. INSERT INTO `perms` VALUES ('perm1''绠$悊鐩綍''dir''/adroot/**''1', '鏃?);  
  36. INSERT INTO `perms` VALUES ('perm2''鐧诲綍椤甸潰''jsp''/login.jsp''0', '鏃?);  
  37. INSERT INTO `perms` VALUES ('perm3''娉ㄥ唽椤甸潰''jsp''/register.jsp''0', '鏃?);  
  38. INSERT INTO `perms` VALUES ('perm4''绯荤粺涓婚〉''jsp''/index.jsp''0', '鏃?);  
  39.   
  40. -- ----------------------------  
  41. -- Table structure for `roles`  
  42. -- ----------------------------  
  43. DROP TABLE IF EXISTS `roles`;  
  44. CREATE TABLE `roles` (  
  45.   `id` varchar(36) NOT NULL,  
  46.   `description` varchar(255) DEFAULT NULL,  
  47.   `rolename` varchar(50) NOT NULL,  
  48.   PRIMARY KEY (`id`),  
  49.   UNIQUE KEY `id` (`id`)  
  50. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
  51.   
  52. -- ----------------------------  
  53. -- Records of roles  
  54. -- ----------------------------  
  55. INSERT INTO `roles` VALUES ('ROLE_ADMIN''绠$悊瑙掕壊''ROLE_ADMIN');  
  56. INSERT INTO `roles` VALUES ('ROLE_ANONYMOUS''璁垮瑙掕壊''ROLE_ANONYMOUS');  
  57. INSERT INTO `roles` VALUES ('ROLE_USER''鐢ㄦ埛瑙掕壊''ROLE_USER');  
  58.   
  59. -- ----------------------------  
  60. -- Table structure for `roles_perms`  
  61. -- ----------------------------  
  62. DROP TABLE IF EXISTS `roles_perms`;  
  63. CREATE TABLE `roles_perms` (  
  64.   `roles_id` varchar(36) NOT NULL,  
  65.   `perms_id` varchar(36) NOT NULL,  
  66.   PRIMARY KEY (`roles_id`,`perms_id`),  
  67.   KEY `FK2E481B81CADB7376` (`perms_id`),  
  68.   KEY `FK2E481B81A0EF5B82` (`roles_id`),  
  69.   CONSTRAINT `FK2E481B81A0EF5B82` FOREIGN KEY (`roles_id`) REFERENCES `roles` (`id`),  
  70.   CONSTRAINT `FK2E481B81CADB7376` FOREIGN KEY (`perms_id`) REFERENCES `perms` (`id`)  
  71. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
  72.   
  73. -- ----------------------------  
  74. -- Records of roles_perms  
  75. -- ----------------------------  
  76. INSERT INTO `roles_perms` VALUES ('ROLE_ADMIN''perm1');  
  77. INSERT INTO `roles_perms` VALUES ('ROLE_ANONYMOUS''perm2');  
  78. INSERT INTO `roles_perms` VALUES ('ROLE_USER''perm2');  
  79. INSERT INTO `roles_perms` VALUES ('ROLE_ANONYMOUS''perm3');  
  80. INSERT INTO `roles_perms` VALUES ('ROLE_USER''perm3');  
  81. INSERT INTO `roles_perms` VALUES ('ROLE_USER''perm4');  
  82.   
  83. -- ----------------------------  
  84. -- Table structure for `users`  
  85. -- ----------------------------  
  86. DROP TABLE IF EXISTS `users`;  
  87. CREATE TABLE `users` (  
  88.   `id` varchar(36) NOT NULL,  
  89.   `username` varchar(50) NOT NULL,  
  90.   `passwordvarchar(32) DEFAULT NULL,  
  91.   `enabled` tinyint(4) DEFAULT '1',  
  92.   `description` varchar(255) DEFAULT '鏃?,  
  93.   PRIMARY KEY (`id`),  
  94.   UNIQUE KEY `id` (`id`)  
  95. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
  96.   
  97. -- ----------------------------  
  98. -- Records of users  
  99. -- ----------------------------  
  100. INSERT INTO `users` VALUES ('admin''admin''admin''1'null);  
  101. INSERT INTO `users` VALUES ('user''user''user''1'null);  
  102.   
  103. -- ----------------------------  
  104. -- Table structure for `users_roles`  
  105. -- ----------------------------  
  106. DROP TABLE IF EXISTS `users_roles`;  
  107. CREATE TABLE `users_roles` (  
  108.   `users_id` varchar(36) NOT NULL,  
  109.   `roles_id` varchar(36) NOT NULL,  
  110.   PRIMARY KEY (`users_id`,`roles_id`),  
  111.   KEY `FKF6CCD9C6A0EF5B82` (`roles_id`),  
  112.   KEY `FKF6CCD9C6A0F27FAC` (`users_id`),  
  113.   CONSTRAINT `FKF6CCD9C6A0EF5B82` FOREIGN KEY (`roles_id`) REFERENCES `roles` (`id`),  
  114.   CONSTRAINT `FKF6CCD9C6A0F27FAC` FOREIGN KEY (`users_id`) REFERENCES `users` (`id`)  
  115. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
  116.   
  117. -- ----------------------------  
  118. -- Records of users_roles  
  119. -- ----------------------------  
  120. INSERT INTO `users_roles` VALUES ('admin''ROLE_ADMIN');  
  121. INSERT INTO `users_roles` VALUES ('admin''ROLE_ANONYMOUS');  
  122. INSERT INTO `users_roles` VALUES ('user''ROLE_ANONYMOUS');  
  123. INSERT INTO `users_roles` VALUES ('admin''ROLE_USER');  
  124. INSERT INTO `users_roles` VALUES ('user''ROLE_USER');  

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

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

[java] view plain copy
  1. package pw.cmos.user.model;  
  2.   
  3. import java.util.HashSet;  
  4. import java.util.Set;  
  5.   
  6. import javax.persistence.Column;  
  7. import javax.persistence.Entity;  
  8. import javax.persistence.FetchType;  
  9. import javax.persistence.GeneratedValue;  
  10. import javax.persistence.Id;  
  11. import javax.persistence.JoinColumn;  
  12. import javax.persistence.JoinTable;  
  13. import javax.persistence.ManyToMany;  
  14. import javax.persistence.Table;  
  15.   
  16. import org.hibernate.annotations.GenericGenerator;  
  17. import org.hibernate.annotations.Proxy;  
  18.   
  19. @Entity  
  20. @Proxy(lazy = false)    
  21. @Table(name = "users", catalog = "mis2013")  
  22. public class User {  
  23.     private String id;  
  24.     private String username;  
  25.     private String password;  
  26.     private boolean enabled;  
  27.     private String description;  
  28.     private Set<Role> roles = new HashSet<Role>();  
  29.   
  30.     @GenericGenerator(name = "generator", strategy = "uuid.hex")  
  31.     @Id  
  32.     @GeneratedValue(generator = "generator")  
  33.     @Column(name = "id", unique = true, nullable = false, length = 36)  
  34.     public String getId() {  
  35.         return id;  
  36.     }  
  37.   
  38.     public void setId(String id) {  
  39.         this.id = id;  
  40.     }  
  41.   
  42.     @Column(name = "username", nullable = false, length = 50)  
  43.     public String getUsername() {  
  44.         return username;  
  45.     }  
  46.   
  47.     public void setUsername(String username) {  
  48.         this.username = username;  
  49.     }  
  50.   
  51.     @Column(name = "password", length = 32)  
  52.     public String getPassword() {  
  53.         return password;  
  54.     }  
  55.   
  56.     public void setPassword(String password) {  
  57.         this.password = password;  
  58.     }  
  59.   
  60.     @Column(name = "enabled")  
  61.     public boolean isEnabled() {  
  62.         return enabled;  
  63.     }  
  64.   
  65.     public void setEnabled(boolean enabled) {  
  66.         this.enabled = enabled;  
  67.     }  
  68.   
  69.     @Column(name = "description", length = 255)  
  70.     public String getDescription() {  
  71.         return description;  
  72.     }  
  73.   
  74.     public void setDescription(String description) {  
  75.         this.description = description;  
  76.     }  
  77.   
  78.     @ManyToMany(targetEntity = Role.class, fetch = FetchType.EAGER)  
  79.     @JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "users_id"), inverseJoinColumns = @JoinColumn(name = "roles_id"))  
  80.     public Set<Role> getRoles() {  
  81.         return roles;  
  82.     }  
  83.   
  84.     public void setRoles(Set<Role> roles) {  
  85.         this.roles = roles;  
  86.     }  
  87.       
  88. }  


 

[java] view plain copy
  1. package pw.cmos.user.model;  
  2.   
  3. import java.util.HashSet;  
  4. import java.util.Set;  
  5.   
  6. import javax.persistence.Column;  
  7. import javax.persistence.Entity;  
  8. import javax.persistence.FetchType;  
  9. import javax.persistence.GeneratedValue;  
  10. import javax.persistence.Id;  
  11. import javax.persistence.JoinColumn;  
  12. import javax.persistence.JoinTable;  
  13. import javax.persistence.ManyToMany;  
  14. import javax.persistence.Table;  
  15.   
  16. import org.hibernate.annotations.GenericGenerator;  
  17.   
  18. @Entity  
  19. @Table(name = "roles", catalog = "mis2013")  
  20. public class Role {  
  21.     private String id;  
  22.     private String rolename;  
  23.     private String description;  
  24.     private Set<User> users = new HashSet<User>();  
  25.     private Set<Perm> perms = new HashSet<Perm>();  
  26.   
  27.     @GenericGenerator(name = "generator", strategy = "uuid.hex")  
  28.     @Id  
  29.     @GeneratedValue(generator = "generator")  
  30.     @Column(name = "id", unique = true, nullable = false, length = 36)  
  31.     public String getId() {  
  32.         return id;  
  33.     }  
  34.   
  35.     public void setId(String id) {  
  36.         this.id = id;  
  37.     }  
  38.   
  39.     @Column(name = "rolename", nullable = false, length = 50)  
  40.     public String getRolename() {  
  41.         return rolename;  
  42.     }  
  43.   
  44.     public void setRolename(String rolename) {  
  45.         this.rolename = rolename;  
  46.     }  
  47.   
  48.     @Column(name = "description", length = 255)  
  49.     public String getDescription() {  
  50.         return description;  
  51.     }  
  52.   
  53.     public void setDescription(String description) {  
  54.         this.description = description;  
  55.     }  
  56.   
  57.     @ManyToMany(mappedBy = "roles")  
  58.     public Set<User> getUsers() {  
  59.         return users;  
  60.     }  
  61.   
  62.     public void setUsers(Set<User> users) {  
  63.         this.users = users;  
  64.     }  
  65.   
  66.     @ManyToMany(targetEntity = Perm.class, fetch = FetchType.EAGER)  
  67.     @JoinTable(name = "roles_perms", joinColumns = @JoinColumn(name = "roles_id"), inverseJoinColumns = @JoinColumn(name = "perms_id"))  
  68.     public Set<Perm> getPerms() {  
  69.         return perms;  
  70.     }  
  71.   
  72.     public void setPerms(Set<Perm> perms) {  
  73.         this.perms = perms;  
  74.     }  
  75. }  

 

[java] view plain copy
  1. package pw.cmos.user.model;  
  2.   
  3. import java.util.HashSet;  
  4. import java.util.Set;  
  5.   
  6. import javax.persistence.Column;  
  7. import javax.persistence.Entity;  
  8. import javax.persistence.FetchType;  
  9. import javax.persistence.GeneratedValue;  
  10. import javax.persistence.Id;  
  11. import javax.persistence.ManyToMany;  
  12. import javax.persistence.Table;  
  13.   
  14. import org.hibernate.annotations.Cache;  
  15. import org.hibernate.annotations.CacheConcurrencyStrategy;  
  16. import org.hibernate.annotations.GenericGenerator;  
  17.   
  18. @Entity  
  19. @Table(name = "perms", catalog = "mis2013")  
  20. public class Perm {  
  21.     private String id;  
  22.     private String permname;  
  23.     private String permtype;  
  24.     private String permstr;  
  25.     private Integer priority;  
  26.     private String description;  
  27.     private Set<Role> roles = new HashSet<Role>();  
  28.   
  29.     @Id  
  30.     @GeneratedValue(generator = "generator")  
  31.     @GenericGenerator(name = "generator", strategy = "uuid.hex")  
  32.     @Column(name = "id", unique = true, nullable = false, length = 36)  
  33.     public String getId() {  
  34.         return id;  
  35.     }  
  36.   
  37.     public void setId(String id) {  
  38.         this.id = id;  
  39.     }  
  40.   
  41.     @Column(name = "permname", nullable = false, length = 50)  
  42.     public String getPermname() {  
  43.         return permname;  
  44.     }  
  45.   
  46.     public void setPermname(String permname) {  
  47.         this.permname = permname;  
  48.     }  
  49.   
  50.     @Column(name = "permtype", length = 15)  
  51.     public String getPermtype() {  
  52.         return permtype;  
  53.     }  
  54.   
  55.     public void setPermtype(String permtype) {  
  56.         this.permtype = permtype;  
  57.     }  
  58.   
  59.     @Column(name = "permstr", length = 255)  
  60.     public String getPermstr() {  
  61.         return permstr;  
  62.     }  
  63.   
  64.     public void setPermstr(String permstr) {  
  65.         this.permstr = permstr;  
  66.     }  
  67.   
  68.     @Column(name = "priority")  
  69.     public Integer getPriority() {  
  70.         return priority;  
  71.     }  
  72.   
  73.     public void setPriority(Integer priority) {  
  74.         this.priority = priority;  
  75.     }  
  76.   
  77.     @Column(name = "description", length = 255)  
  78.     public String getDescription() {  
  79.         return description;  
  80.     }  
  81.   
  82.     public void setDescription(String description) {  
  83.         this.description = description;  
  84.     }  
  85.   
  86.     @ManyToMany(mappedBy = "perms", targetEntity = Role.class, fetch = FetchType.EAGER)  
  87.     public Set<Role> getRoles() {  
  88.         return roles;  
  89.     }  
  90.   
  91.     public void setRoles(Set<Role> roles) {  
  92.         this.roles = roles;  
  93.     }  
  94.   
  95. }  


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

[java] view plain copy
  1. package pw.cmos.user.dao;  
  2.   
  3. import org.hibernate.Session;  
  4. import org.hibernate.SessionFactory;  
  5. import org.springframework.beans.factory.annotation.Autowired;  
  6.   
  7. public class BaseDAO {  
  8.     @Autowired  
  9.     private SessionFactory sessionFactory;  
  10.   
  11.     public SessionFactory getSessionFactory() {  
  12.         return sessionFactory;  
  13.     }  
  14.       
  15.     public Session getSession() {  
  16.         return sessionFactory.getCurrentSession();  
  17.     }  
  18. }  

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

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

[java] view plain copy
  1. package pw.cmos.user.dao;  
  2.   
  3. import java.util.List;  
  4. import pw.cmos.user.model.User;  
  5.   
  6. public interface IUserDAO {  
  7.   
  8.     public abstract void save(User user);  
  9.   
  10.     public abstract void delete(User user);  
  11.   
  12.     public abstract User findUserById(final String id);  
  13.   
  14.     public abstract User findUserByUsername(final String username);  
  15.   
  16.     public abstract List findByProperty(String propertyName, Object value);  
  17.   
  18.     public abstract User getUserByName(String username);  
  19.   
  20.     public abstract List<String> loadUserAuthoritiesByName(String username);  
  21.   
  22. }  


 

[java] view plain copy
  1. package pw.cmos.user.dao;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Iterator;  
  5. import java.util.List;  
  6. import java.util.Set;  
  7.   
  8. import org.hibernate.Query;  
  9. import org.hibernate.Session;  
  10. import org.springframework.stereotype.Repository;  
  11.   
  12. import pw.cmos.user.model.Role;  
  13. import pw.cmos.user.model.User;  
  14.   
  15. @Repository  
  16. public class UserDAO extends BaseDAO implements IUserDAO {  
  17.   
  18.     @Override  
  19.     public void save(User user) {  
  20.     }  
  21.   
  22.     @Override  
  23.     public void delete(User user) {  
  24.         // TODO Auto-generated method stub  
  25.   
  26.     }  
  27.   
  28.     @Override  
  29.     public User findUserById(String id) {  
  30.         // TODO Auto-generated method stub  
  31.         return null;  
  32.     }  
  33.   
  34.     @Override  
  35.     public User findUserByUsername(String username) {  
  36.         // TODO Auto-generated method stub  
  37.         return null;  
  38.     }  
  39.   
  40.     @Override  
  41.     public List findByProperty(String propertyName, Object value) {  
  42.         // TODO Auto-generated method stub  
  43.         return null;  
  44.     }  
  45.   
  46.     public User getUserByName(String username) {  
  47.         Session s = getSession();  
  48.         Query query = s.createQuery("from User as u where u.username = ?");  
  49.         query.setString(0, username);  
  50.         User user = (User) query.uniqueResult();  
  51.         return user;  
  52.     }  
  53.   
  54.     public List<String> loadUserAuthoritiesByName(String username) {  
  55.         User user = this.getUserByName(username);  
  56.         if (user != null) {  
  57.             Set<Role> roles = user.getRoles();  
  58.             List<String> auth = new ArrayList<String>();  
  59.             Iterator<Role> it = roles.iterator();  
  60.             while (it.hasNext()) {  
  61.                 auth.add(((Role) it.next()).getRolename());  
  62.             }  
  63.             return auth;  
  64.         } else {  
  65.             return null;  
  66.         }  
  67.     }  
  68. }  

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

[java] view plain copy
  1. package pw.cmos.user.dao;  
  2.   
  3. import java.util.List;  
  4.   
  5. import pw.cmos.user.model.Perm;  
  6.   
  7. public interface IPermDAO {  
  8.   
  9.     public abstract void save(Perm perm);  
  10.   
  11.     public abstract void delete(Perm perm);  
  12.   
  13.     public abstract Perm findPermById(final String id);  
  14.   
  15.     public abstract Perm findPermByPermname(final String permname);  
  16.   
  17.     public abstract List<Perm> findPermByUri(final String requestUri);  
  18.   
  19.     public abstract List findByProperty(String propertyName, Object value);  
  20. }  
[java] view plain copy
  1. package pw.cmos.user.dao;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import org.hibernate.Query;  
  7. import org.hibernate.Session;  
  8. import org.hibernate.Transaction;  
  9. import org.springframework.stereotype.Repository;  
  10. import org.springframework.util.AntPathMatcher;  
  11. import org.springframework.util.PathMatcher;  
  12.   
  13. import pw.cmos.user.model.Perm;  
  14.   
  15. @Repository  
  16. public class PermDAO extends BaseDAO implements IPermDAO {  
  17.   
  18.     @Override  
  19.     public void save(Perm perm) {  
  20.         // TODO Auto-generated method stub  
  21.   
  22.     }  
  23.   
  24.     @Override  
  25.     public void delete(Perm perm) {  
  26.         // TODO Auto-generated method stub  
  27.   
  28.     }  
  29.   
  30.     @Override  
  31.     public Perm findPermById(String id) {  
  32.         // TODO Auto-generated method stub  
  33.         return null;  
  34.     }  
  35.   
  36.     @Override  
  37.     public Perm findPermByPermname(String permname) {  
  38.         // TODO Auto-generated method stub  
  39.         return null;  
  40.     }  
  41.   
  42.     @Override  
  43.     public List<Perm> findPermByUri(String requestUri) {  
  44.         Session s = getSession();  
  45.         Query query = s.createQuery("from Perm");  
  46.         List<Perm> permlist = query.list();  
  47.         List<Perm> perms = new ArrayList<Perm>();  
  48.         for (Perm perm : permlist) {  
  49.             if (urlMatcher(perm.getPermstr(), requestUri))  
  50.                 perms.add(perm);  
  51.         }  
  52.         return perms;  
  53.     }  
  54.   
  55.     private boolean urlMatcher(String permstr, String requestUri) {  
  56.         boolean isMatcher = false;  
  57.         PathMatcher matcher = new AntPathMatcher();  
  58.         isMatcher = matcher.match(permstr, requestUri);  
  59.         return isMatcher;  
  60.     }  
  61.   
  62.     @Override  
  63.     public List findByProperty(String propertyName, Object value) {  
  64.         // TODO Auto-generated method stub  
  65.         return null;  
  66.     }  
  67.   
  68. }  

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

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

web.xml代码如下:

[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.     xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  
  4.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"  
  5.     id="WebApp_ID" version="3.0">  
  6.     <display-name>mis2013</display-name>  
  7.     <welcome-file-list>  
  8.         <welcome-file>index.html</welcome-file>  
  9.         <welcome-file>index.htm</welcome-file>  
  10.         <welcome-file>index.jsp</welcome-file>  
  11.         <welcome-file>default.html</welcome-file>  
  12.         <welcome-file>default.htm</welcome-file>  
  13.         <welcome-file>default.jsp</welcome-file>  
  14.     </welcome-file-list>  
  15.       
  16.     <context-param>  
  17.         <param-name>contextConfigLocation</param-name>  
  18.         <param-value>classpath:Context.xml,classpath:Security.xml</param-value>  
  19.     </context-param>  
  20.     <!-- 配置spiring security -->  
  21.     <filter>  
  22.         <filter-name>springSecurityFilterChain</filter-name>  
  23.         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  24.     </filter>  
  25.     <filter-mapping>  
  26.         <filter-name>springSecurityFilterChain</filter-name>  
  27.         <url-pattern>/*</url-pattern>  
  28.     </filter-mapping>  
  29.     <!-- 配置spiring security结束 -->  
  30.     <listener>  
  31.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  32.     </listener>   
  33.     <filter>  
  34.         <filter-name>struts2</filter-name>  
  35.         <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>  
  36.     </filter>  
  37.     <filter-mapping>  
  38.         <filter-name>struts2</filter-name>  
  39.         <url-pattern>/*</url-pattern>  
  40.     </filter-mapping>  
  41. </web-app>  

 

login.jsp代码如下:

[html] view plain copy
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  
  2. <%@taglib prefix="s" uri="/struts-tags"%>  
  3. <%@ taglib prefix="sec"  
  4.     uri="http://www.springframework.org/security/tags"%>  
  5. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  6. <html>  
  7. <head>  
  8. <title>用户登陆</title>  
  9. </head>  
  10.   
  11. <body>  
  12.     <a href="<s:url value='/index.jsp'/>">首页</a>  
  13.     <a href="<s:url value='/register.jsp'/>">注册</a>  
  14.     <hr size="1" />  
  15.     <s:form action="/j_spring_security_check" method="POST" namespace="/user">  
  16.         <s:fielderror></s:fielderror>  
  17.         <s:textfield key="用户" name="j_username"></s:textfield>  
  18.         <s:password key="密码" name="j_password" style="width:155px;"></s:password>  
  19.         <s:submit value="登陆系统"></s:submit>  
  20.         <s:actionerror />  
  21.     </s:form>  
  22. </body>  
  23. </html>  

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


Comtext.xml代码如下:

[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  
  4.     xmlns:context="http://www.springframework.org/schema/context"  
  5.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"  
  6.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  7.     http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
  8.     http://www.springframework.org/schema/context   
  9.     http://www.springframework.org/schema/context/spring-context-3.1.xsd   
  10.     http://www.springframework.org/schema/aop   
  11.     http://www.springframework.org/schema/aop/spring-aop-3.1.xsd  
  12.     http://www.springframework.org/schema/tx   
  13.     http://www.springframework.org/schema/tx/spring-tx-3.1.xsd  ">  
  14.   
  15.     <context:component-scan base-package="pw.cmos" />  
  16.   
  17.     <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">  
  18.         <property name="driverClassName" value="com.mysql.jdbc.Driver" />  
  19.         <property name="url" value="jdbc:mysql://localhost:3306/mis2013">  
  20.         </property>  
  21.         <property name="username" value="root"></property>  
  22.         <property name="password" value="******"></property>  
  23.     </bean>  
  24.   
  25.     <bean id="sessionFactory"  
  26.         class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">  
  27.         <property name="dataSource">  
  28.             <ref bean="dataSource" />  
  29.         </property>  
  30.         <property name="hibernateProperties">  
  31.             <props>  
  32.                 <prop key="hibernate.show_sql">true</prop>  
  33.                 <prop key="hibernate.dialect">  
  34.                     org.hibernate.dialect.MySQLDialect  
  35.                 </prop>  
  36.                 <prop key="hibernate.hbm2ddl.auto">update</prop>  
  37.             </props>  
  38.         </property>  
  39.         <property name="annotatedClasses">  
  40.             <list>  
  41.                 <value>pw.cmos.user.model.User</value>  
  42.                 <value>pw.cmos.user.model.Role</value>  
  43.                 <value>pw.cmos.user.model.Perm</value>  
  44.             </list>  
  45.         </property>  
  46.     </bean>  
  47.       
  48.     <!-- 开启注解事务 只对当前配置文件有效 -->  
  49.     <tx:annotation-driven transaction-manager="txManager" />  
  50.     <bean id="txManager"  
  51.         class="org.springframework.orm.hibernate4.HibernateTransactionManager">  
  52.         <property name="sessionFactory" ref="sessionFactory" />  
  53.     </bean>  
  54.   
  55.     <tx:advice id="txAdvice" transaction-manager="txManager">  
  56.         <tx:attributes>  
  57.             <tx:method name="save*" propagation="REQUIRED" />  
  58.             <tx:method name="add*" propagation="REQUIRED" />  
  59.             <tx:method name="create*" propagation="REQUIRED" />  
  60.             <tx:method name="insert*" propagation="REQUIRED" />  
  61.             <tx:method name="*" read-only="true" />  
  62.         </tx:attributes>  
  63.     </tx:advice>  
  64.   
  65.     <aop:config proxy-target-class="true">  
  66.         <aop:pointcut id="dao" expression="execution(* pw.cmos..dao.*.*(..))" />  
  67.         <aop:advisor pointcut-ref="dao" advice-ref="txAdvice" />  
  68.     </aop:config>  
  69. </beans>  

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

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

[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans:beans xmlns="http://www.springframework.org/schema/security"  
  3.     xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  5.                         http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">  
  6.   
  7.     <http pattern="/login.jsp" security="none" />  
  8.     <http pattern="/accessDenied.jsp" security="none" />  
  9.   
  10.     <http auto-config="true">  
  11.         <form-login login-page="/login.jsp"  
  12.             authentication-failure-url="/login.jsp" />  
  13.         <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" />  
  14.     </http>  
  15.   
  16.     <beans:bean id="myFilter"  
  17.         class="pw.cmos.web.security.MyFilterSecurityInterceptor">  
  18.         <beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />  
  19.         <beans:property name="authenticationManager" ref="authenticationManager" />  
  20.         <beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />  
  21.     </beans:bean>  
  22.   
  23.     <authentication-manager alias="authenticationManager">  
  24.         <authentication-provider user-service-ref="myUserDetailsService">  
  25.         </authentication-provider>  
  26.     </authentication-manager>  
  27.    
  28.     <beans:bean name="myUserDetailsService" class="pw.cmos.web.security.MyUserDetailsService">  
  29.     </beans:bean>  
  30.   
  31.     <beans:bean name="myAccessDecisionManager"  
  32.         class="pw.cmos.web.security.MyAccessDecisionManager">  
  33.     </beans:bean>  
  34.   
  35.     <beans:bean name="mySecurityMetadataSource"  
  36.         class="pw.cmos.web.security.MyInvocationSecurityMetadataSourceService">  
  37.     </beans:bean>  
  38.   
  39. </beans:beans>  

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

[java] view plain copy
  1. package pw.cmos.web.security;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.Filter;  
  6. import javax.servlet.FilterChain;  
  7. import javax.servlet.FilterConfig;  
  8. import javax.servlet.ServletException;  
  9. import javax.servlet.ServletRequest;  
  10. import javax.servlet.ServletResponse;  
  11.   
  12. import org.springframework.security.access.SecurityMetadataSource;  
  13. import org.springframework.security.access.intercept.AbstractSecurityInterceptor;  
  14. import org.springframework.security.access.intercept.InterceptorStatusToken;  
  15. import org.springframework.security.web.FilterInvocation;  
  16. import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;  
  17.   
  18. public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor  
  19.         implements Filter {  
  20.   
  21.     private FilterInvocationSecurityMetadataSource securityMetadataSource;  
  22.   
  23.     @Override  
  24.     public void init(FilterConfig filterConfig) throws ServletException {  
  25.     }  
  26.   
  27.     @Override  
  28.     public void doFilter(ServletRequest request, ServletResponse response,  
  29.             FilterChain chain) throws IOException, ServletException {  
  30.         FilterInvocation fi = new FilterInvocation(request, response, chain);  
  31.         invoke(fi);  
  32.   
  33.     }  
  34.   
  35.     @Override  
  36.     public void destroy() {  
  37.     }  
  38.   
  39.     @Override  
  40.     public Class<?> getSecureObjectClass() {  
  41.         return FilterInvocation.class;  
  42.     }  
  43.   
  44.     @Override  
  45.     public SecurityMetadataSource obtainSecurityMetadataSource() {  
  46.         return this.securityMetadataSource;  
  47.     }  
  48.   
  49.     public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {  
  50.         return this.securityMetadataSource;  
  51.     }  
  52.   
  53.     public void invoke(FilterInvocation fi) throws IOException,  
  54.             ServletException {  
  55.         InterceptorStatusToken token = super.beforeInvocation(fi);  
  56.         try {  
  57.             fi.getChain().doFilter(fi.getRequest(), fi.getResponse());  
  58.         } finally {  
  59.             super.afterInvocation(token, null);  
  60.         }  
  61.     }  
  62.   
  63.     public void setSecurityMetadataSource(  
  64.             FilterInvocationSecurityMetadataSource securityMetadataSource) {  
  65.         this.securityMetadataSource = securityMetadataSource;  
  66.     }  
  67.   
  68. }  


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

[java] view plain copy
  1. package pw.cmos.web.security;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Collection;  
  5. import java.util.List;  
  6.   
  7. import org.springframework.beans.factory.annotation.Autowired;  
  8. import org.springframework.security.core.GrantedAuthority;  
  9. import org.springframework.security.core.authority.SimpleGrantedAuthority;  
  10. import org.springframework.security.core.userdetails.UserDetails;  
  11. import org.springframework.security.core.userdetails.UserDetailsService;  
  12. import org.springframework.security.core.userdetails.UsernameNotFoundException;  
  13.   
  14. import pw.cmos.user.dao.IUserDAO;  
  15. import pw.cmos.user.dao.UserDAO;  
  16. import pw.cmos.user.model.User;  
  17.   
  18. public class MyUserDetailsService implements UserDetailsService {  
  19.   
  20.     @Autowired  
  21.     private IUserDAO userDao;  
  22.   
  23.     @Override  
  24.     public UserDetails loadUserByUsername(String username)  
  25.             throws UsernameNotFoundException {  
  26.         Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();  
  27.         User user = new User();  
  28.         try {  
  29.             user = userDao.getUserByName(username);  
  30.             List<String> authStr = userDao.loadUserAuthoritiesByName(username);  
  31.             for (String authName : authStr) {  
  32.                 SimpleGrantedAuthority authority = new SimpleGrantedAuthority(  
  33.                         authName);  
  34.                 auths.add(authority);  
  35.             }  
  36.         } catch (Exception e) {  
  37.             e.printStackTrace();  
  38.         }  
  39.         return new org.springframework.security.core.userdetails.User(  
  40.                 user.getUsername(), user.getPassword(), truetruetruetrue,  
  41.                 auths);  
  42.     }  
  43.   
  44. }  


 

[java] view plain copy
  1. package pw.cmos.web.security;  
  2.   
  3. import java.util.Collection;  
  4. import java.util.Iterator;  
  5.   
  6. import org.springframework.security.access.AccessDecisionManager;  
  7. import org.springframework.security.access.AccessDeniedException;  
  8. import org.springframework.security.access.ConfigAttribute;  
  9. import org.springframework.security.access.SecurityConfig;  
  10. import org.springframework.security.authentication.InsufficientAuthenticationException;  
  11. import org.springframework.security.core.Authentication;  
  12. import org.springframework.security.core.GrantedAuthority;  
  13.   
  14. public class MyAccessDecisionManager implements AccessDecisionManager {  
  15.   
  16.     @Override  
  17.     public void decide(Authentication authentication, Object object,  
  18.             Collection<ConfigAttribute> configAttributes)  
  19.             throws AccessDeniedException, InsufficientAuthenticationException {  
  20.         if (configAttributes == null) {  
  21.             return;  
  22.         }  
  23.   
  24.         Iterator<ConfigAttribute> ite = configAttributes.iterator();  
  25.   
  26.         while (ite.hasNext()) {  
  27.             ConfigAttribute ca = ite.next();  
  28.             String needRole = ((SecurityConfig) ca).getAttribute();  
  29.             for (GrantedAuthority ga : authentication.getAuthorities()) {  
  30.                 if (needRole.trim().equals(ga.getAuthority().trim())) {  
  31.                     return;  
  32.                 }  
  33.             }  
  34.         }  
  35.         throw new AccessDeniedException("无权限!");  
  36.   
  37.     }  
  38.   
  39.     @Override  
  40.     public boolean supports(ConfigAttribute attribute) {  
  41.         return true;  
  42.     }  
  43.   
  44.     @Override  
  45.     public boolean supports(Class<?> clazz) {  
  46.         return true;  
  47.     }  
  48.   
  49. }  

 

[java] view plain copy
  1. package pw.cmos.web.security;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Collection;  
  5. import java.util.List;  
  6. import java.util.Set;  
  7.   
  8. import org.springframework.beans.factory.annotation.Autowired;  
  9. import org.springframework.security.access.ConfigAttribute;  
  10. import org.springframework.security.access.SecurityConfig;  
  11. import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;  
  12. import org.springframework.security.web.FilterInvocation;  
  13.   
  14. import pw.cmos.user.dao.IPermDAO;  
  15. import pw.cmos.user.dao.PermDAO;  
  16. import pw.cmos.user.model.Perm;  
  17. import pw.cmos.user.model.Role;  
  18.   
  19. public class MyInvocationSecurityMetadataSourceService implements  
  20.         FilterInvocationSecurityMetadataSource {  
  21.   
  22.     @Autowired  
  23.     private IPermDAO permDao;  
  24.   
  25.     @Override  
  26.     public Collection<ConfigAttribute> getAttributes(Object object)  
  27.             throws IllegalArgumentException {  
  28.         String url = ((FilterInvocation) object).getRequestUrl();  
  29.         int firstQuestionMarkIndex = url.indexOf("?");  
  30.         if (firstQuestionMarkIndex != -1) {  
  31.             url = url.substring(0, firstQuestionMarkIndex);  
  32.         }  
  33.         System.out.println("url:" + url);  
  34.         List<ConfigAttribute> result = new ArrayList<ConfigAttribute>();  
  35.         ConfigAttribute attribute = new SecurityConfig("ROLE_BASE");  
  36.         result.add(attribute);  
  37.         try {  
  38.             List<Perm> permList = permDao.findPermByUri(url);  
  39.             if (permList != null && permList.size() > 0) {  
  40.                 for (Perm perm : permList) {  
  41.                     Set<Role> roles = perm.getRoles();  
  42.                     if (roles != null && roles.size() > 0) {  
  43.                         for (Role role : roles) {  
  44.                             ConfigAttribute conf = new SecurityConfig(  
  45.                                     role.getRolename());  
  46.                             result.add(conf);  
  47.                         }  
  48.                     }  
  49.                 }  
  50.             }  
  51.   
  52.         } catch (Exception e) {  
  53.             e.printStackTrace();  
  54.         }  
  55.         return result;  
  56.     }  
  57.   
  58.     @Override  
  59.     public Collection<ConfigAttribute> getAllConfigAttributes() {  
  60.         // TODO Auto-generated method stub  
  61.         return null;  
  62.     }  
  63.   
  64.     @Override  
  65.     public boolean supports(Class<?> clazz) {  
  66.         // TODO Auto-generated method stub  
  67.         return true;  
  68.     }  
  69.   
  70. }  

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

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值