spring security 阶段总结: mvc + hibernate +mysql 实现的例子

摘要: 利用业余时间初步研究了几天 spring security, 现在是时候做一个阶段性总结了,利用 spring mvc , spring security, hibernate, mysql 实现一个基于数据库的简单权限系统, 功能不复杂,但麻雀虽小,五脏俱全。目标如下:1. 用户和角色存储在数据库中2. 不同的角色访问不同的页面. 如果不没有权限,则出 403 错误页面 (可以参考前面的文章定制一个.), ROLE_USER  角色的用户,只能访问user 页面,而 ROLE_ADMIN 角色的用户可以访问 admin1,admin2 user页面.提供整个程序的代码下载。在本文的最后,应该本文只挑重点的讲,其他的可以看代码.

利用业余时间初步研究了几天 spring security, 现在是时候做一个阶段性总结了,利用 spring mvc , spring security, hibernate, mysql 实现一个基于数据库的简单权限系统, 功能不复杂,但麻雀虽小,五脏俱全。目标如下:
1. 用户和角色存储在数据库中
2. 不同的角色访问不同的页面. 如果不没有权限,则出 403 错误页面 (可以参考前面的文章定制一个.), ROLE_USER 角色的用户,只能访问user 页面,而 ROLE_ADMIN 角色的用户可以访问 admin1,admin2 user页面.

提供整个程序的代码下载。在本文的最后,应该本文只挑重点的讲,其他的可以看代码.
准备, 我用到的jar 包如下,有可能多余, 但注意 hibernate 需要的包包含jboss的包是不可以缺少的,清单如下:

antlr-2.7.7.jar
aopalliance.jar
aspectjweaver.jar
commons-collections.jar
commons-logging-1.1.jar
dom4j-1.6.1.jar
ehcache-core-2.4.3.jar
hibernate-commons-annotations-4.0.1.Final.jar
hibernate-core-4.0.0.Final.jar
hibernate-ehcache-4.0.0.Final.jar
hibernate-entitymanager-4.0.0.Final.jar
hibernate-jpa-2.0-api-1.0.1.Final.jar
javassist-3.12.1.GA.jar
jboss-logging-3.1.0.CR2.jar
jboss-transaction-api_1.1_spec-1.0.0.Final.jar
jstl-1.1.2.jar
log4j-1.2.13.jar
mysql-connector-java-3.1.12-bin.jar
slf4j-api-1.5.2.jar
slf4j-log4j12-1.5.2.jar
spring-aop-3.2.4.RELEASE.jar
spring-aspects-3.2.4.RELEASE.jar
spring-beans-3.2.4.RELEASE.jar
spring-context-3.2.4.RELEASE.jar
spring-context-support-3.2.4.RELEASE.jar
spring-core-3.2.4.RELEASE.jar
spring-expression-3.2.4.RELEASE.jar
spring-jdbc-3.2.4.RELEASE.jar
spring-orm-3.2.4.RELEASE.jar
spring-security-config-3.1.4.RELEASE.jar
spring-security-core-3.1.4.RELEASE.jar
spring-security-web-3.1.4.RELEASE.jar
spring-tx-3.2.4.RELEASE.jar
spring-web-3.2.4.RELEASE.jar
spring-webmvc-3.2.4.RELEASE.jar
standard-1.1.2.jar


数据库的准备

-- ----------------------------
-- Table structure for `roles`
-- ----------------------------
Drop TABLE IF EXISTS `roles`;
Create TABLE `roles` (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `role` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of roles
-- ----------------------------
Insert INTO `roles` VALUES ('1', 'ROLE_ADMIN');
Insert INTO `roles` VALUES ('2', 'ROLE_USER');

-- ----------------------------
-- Table structure for `users`
-- ----------------------------
Drop TABLE IF EXISTS `users`;
Create TABLE `users` (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `login` varchar(20) NOT NULL,
  `password` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of users
-- ----------------------------
Insert INTO `users` VALUES ('1', 'yihaomen', '123456');
Insert INTO `users` VALUES ('2', 'admin', '123456');

-- ----------------------------
-- Table structure for `user_roles`
-- ----------------------------
Drop TABLE IF EXISTS `user_roles`;
Create TABLE `user_roles` (
  `user_id` int(6) NOT NULL,
  `role_id` int(6) NOT NULL,
  KEY `user` (`user_id`),
  KEY `role` (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user_roles
-- ----------------------------
Insert INTO `user_roles` VALUES ('1', '2');
Insert INTO `user_roles` VALUES ('2', '1');


整个工程如下图所示:



至于 spring security 的基础配置,不解释了,只想详细介绍下 CustomUserDetailsService , 这是关键,用户认证,角色的获取以及授权都是这样获得的.

package com.yihaomen.service;

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.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.yihaomen.dao.UserDAO;

@Service
@Transactional(readOnly=true)
public class CustomUserDetailsService implements UserDetailsService {
	
	@Autowired
	private UserDAO userDAO;	

	public UserDetails loadUserByUsername(String login)
			throws UsernameNotFoundException {
		/*这里是认证*/
		com.yihaomen.model.User domainUser = userDAO.getUser(login);
		
		boolean enabled = true;
		boolean accountNonExpired = true;
		boolean credentialsNonExpired = true;
		boolean accountNonLocked = true;

		return new User(
				domainUser.getLogin(), 
				domainUser.getPassword(), 
				enabled, 
				accountNonExpired, 
				credentialsNonExpired, 
				accountNonLocked,
				getAuthorities(domainUser.getRole().getId())
		);
	}
	
	public Collection getAuthorities(Integer role) {
		List authList = getGrantedAuthorities(getRoles(role));
		return authList;
	}
	
	public List getRoles(Integer role) {

		List roles = new ArrayList();
        /*这里还可以写的更灵活或者更好,暂且这样吧. hardcode的,做灵活也容易,试验局,就这样了。*/
		if (role.intValue() == 1) {
			roles.add("ROLE_USER");
			roles.add("ROLE_ADMIN");
		} else if (role.intValue() == 2) {
			roles.add("ROLE_USER");
		}
		return roles;
	}
	
	public static List getGrantedAuthorities(List roles) {
		/*这是授权*/
		List authorities = new ArrayList();		
		for (String role : roles) {
			authorities.add(new SimpleGrantedAuthority(role));
		}
		return authorities;
	}

}



spring security 配置文件核心部分如下

    	
		
		
		
		
		    
	    	 
	
	
	
	
	
	
		
			
		
	


spring 与 hibernate4 的集成


        
            
                classpath:resources.properties
            
        
    

	
		
		
		
		
	
	
	
	
	
	
    	
    	
    	
			
				com.yihaomen
			
		
		 
        
            
                ${hibernate.dialect}
                ${hibernate.show_sql}
                true
                ${hibernate.query.substitutions}
                ${hibernate.default_batch_fetch_size}
                ${hibernate.max_fetch_depth}
                ${hibernate.generate_statistics}
                ${hibernate.bytecode.use_reflection_optimizer}

                ${hibernate.cache.use_second_level_cache}
                ${hibernate.cache.use_query_cache}
                ${hibernate.cache.region.factory_class}
                ${net.sf.ehcache.configurationResourceName}
                ${hibernate.cache.use_structured_entries}
            
        
  	


    
	
	
	
  	

    
        
    

    
        
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
        
    
    
        
        
        
    
		


用户实体类,角色实体类
package com.yihaomen.model;

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name="roles")
public class Role {
	
	@Id
	@GeneratedValue
	private Integer id;
	
	private String role;
	
	@OneToMany(cascade=CascadeType.ALL)
	@JoinTable(name="user_roles", 
		joinColumns = {@JoinColumn(name="role_id", referencedColumnName="id")},
		inverseJoinColumns = {@JoinColumn(name="user_id", referencedColumnName="id")}
	)
	private Set userRoles;

	public Integer getId() {
		return id;
	}

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

	public String getRole() {
		return role;
	}

	public void setRole(String role) {
		this.role = role;
	}

	public Set getUserRoles() {
		return userRoles;
	}

	public void setUserRoles(Set userRoles) {
		this.userRoles = userRoles;
	}
	
}

package com.yihaomen.model;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name="users")
public class User {
	
	@Id
	@GeneratedValue
	private Integer id;
	
	private String login;
	
	private String password;
	
	@OneToOne(cascade=CascadeType.ALL)
	@JoinTable(name="user_roles",
		joinColumns = {@JoinColumn(name="user_id", referencedColumnName="id")},
		inverseJoinColumns = {@JoinColumn(name="role_id", referencedColumnName="id")}
	)
	private Role role;

	public Integer getId() {
		return id;
	}

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

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getPassword() {
		return password;
	}

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

	public Role getRole() {
		return role;
	}

	public void setRole(Role role) {
		this.role = role;
	}	

}



另外 spring mvc 控制层编写就比较简单了,dao 层与 service 的编写就如同平常的程序一样,没有什么特殊的,由于提供了代码下载, 所以也就不详细介绍了。

整个应用程序运行起来后的结果如下:




这个时候,点击先关超级连接的时候,根据用户的权限不同,可能出现不同的页面或者 403 页面.

注意事项
1. 如果出现如下错误:java.lang.IllegalArgumentException: Failed to evaluate expression 'ROLE_ADMIN' ,类似错误的时候,注意检查spring security配置: , 还有一种配置方式是使用spring spel表达式:
 
......	
access="hasRole('ROLE_XXX) or hasRole('ROLE_YYY')"
这种形式


2.在用hibernate4 的时候,我遇到了sessionFactory 没有办法在dao层 autowire ,自动注入的问题. 后来发现是少了javassist-3.12.1.GA.jar 这个包。

虽然这个例子还不是很完善,但应付一般的权限系统,应该可以了,如果有时间,还需要加强,至少把 资源的管理也纳入数据中,这样就比较完善了。

整个代码下载, 省略了jar 包,太大了,没空间. 可以参考 我前面提供的 jar 清单.

spring mvc, spring security,hibernate,mysql 例子下载.

上一篇: spring security 登录根据用户角色跳转到不同的页面
下一篇: spring security 教程入门
 评论 ( What Do You Think )
名称
邮箱
网址
评论
验证
   
 

 


  • 微信公众号

  • 我的微信

站点声明:

1、一号门博客CMS,由Python, MySQL, Nginx, Wsgi 强力驱动

2、部分文章或者资源来源于互联网, 有时候很难判断是否侵权, 若有侵权, 请联系邮箱:summer@yihaomen.com, 同时欢迎大家注册用户,主动发布无版权争议的 文章/资源.

3、鄂ICP备14001754号-3, 鄂公网安备 42280202422812号