Shiro集成Spring

本篇博客主要讲述的是两者的集成,不涉及到各自的具体细节和功能。

由于官方给出的文档不够详细,对新手而言通过官方文档还不能够很快的搭建出SpringShiro的web工程,本博客将通过实际的案例提供具体的教程。

案例分析:

 

项目名称:假期系统

组织机构:部门 > 小组

角色:Admin, SeniorManager,TeamLeader,Developer

资源:假期Leave

权限:申请Apply,审核Review, 复核ReReview,查看View

角色级别:Admin > Senior Manager >Team Leader > Developer

角色权限:

 

Admin

Senior Manager

Team Leader

Developer

Apply

Y

Y

Y

Y

Review

Y

Y

Y

N

ReReview

Y

Y

N

N

View

Y

Y

Y

Y

 

特殊需求:

1. 角色可以绑定到不同的组织机构级别,比如SeniorManager 是基于部门的,TeamLeader则是基于小组的

2. 角色的级别关系只能在相同的部门中,不同部门之间的角色没有关联

3. 审核只能是自己上级角色审核,复核必须是审核者的上级角色复核,即Developer提出的请假申请只能TeamLeader来审核,并且由SeniorManager复核。

 

数据库设计

 

最简单的数据库设计如下:

表名

列名

描述

类型

t_dept

部门表

id

部门编号

Int

name

部门名称

Varchar

 

t_team

小组表

id

小组编号

Int

name

小组名称

Varchar

 

t_user

用户表

id

用户编号

Int

username

用户名称

Varchar

password

用户加密密码

Varchar

salt

用户加密盐

Varchar

manager_id

用户上级领导id

Int

 

t_role

角色表

id

角色编号

Int

name

角色名称

Varchar

dept_flag

角色是否关联部门

Bool

team_flag

角色是否关联小组

Bool

 

t_user_role

用户所属角色表

Id

用户角色编号

Int

user_id

用户编号

Int

dept_id

部门编号

Int

team_id

小组编号

Int

role_id

角色编号

Int

 

t_resource

资源表

id

资源编号

Int

name

资源名称

Varchar

 

t_permission

权限表

id

权限编号

Int

name

权限名称

Varchar

 

t_role_resource_permission

角色拥有的资源权限表

id

编号

Int

role_id

角色编号

Int

resource_id

资源编号

Int

permission_id

权限编号

Int

 

 

 

 

t_leave

请假申请表

id

请假申请编号

Int

user_id

请假者编号

Int

days

请假时长

Int

fromDate

开始日期

Date

toDate

结束日期

Date

remark

请假说明

Varchar

flag

请假状态

Int

apply_date

申请的时间

Datetime

review_user_id

审核人编号

Int

review_date

审核日期

Date

review_remark

审核说明

Varchar

rereview_user_id

复核人编号

Int

rereview_date

复核日期

Date

rereview_remark

复核说明

Varchar

 

添加测试数据:

Shiro集成Spring_第1张图片

项目搭建

Maven Project: pom.xml

新建一个maven项目,packaging设定为war,设定Spring和Shiro的版本为3.1.4.RELEASE和1.2.3,并添加必要的依赖。具体如下:


	4.0.0
	com.xx.shiro
	demo
	1.0.0
	war

	
		1.7
		3.1.4.RELEASE
		UTF-8
		1.2.3
	

	
		
		
			javax
			javaee-api
			6.0
			provided
		

		
		
			org.springframework
			spring-context
			${org.springframework-version}
			
				
				
					commons-logging
					commons-logging
				
			
		

		
		
			org.springframework
			spring-webmvc
			${org.springframework-version}
		
		
			org.springframework
			spring-core
			${org.springframework-version}
		

		
			org.springframework
			spring-jdbc
			${org.springframework-version}
		

		
			org.springframework
			spring-aop
			${org.springframework-version}
		

		
			org.springframework
			spring-tx
			${org.springframework-version}
		
		
		
		
			org.apache.shiro
			shiro-core
			${org.shiro-version}
		
		
			org.apache.shiro
			shiro-ehcache
			${org.shiro-version}
		
		
			org.apache.shiro
			shiro-web
			${org.shiro-version}
		
		
			org.apache.shiro
			shiro-quartz
			${org.shiro-version}
		
		
			org.apache.shiro
			shiro-spring
			${org.shiro-version}
		
		

		
		
			org.codehaus.jackson
			jackson-core-asl
			1.8.8
		
		
			org.codehaus.jackson
			jackson-mapper-asl
			1.8.8
		

		
		
			commons-lang
			commons-lang
			2.6
		

		
		
			commons-io
			commons-io
			2.4
		

		
		
			jstl
			jstl
			1.2
		

		
		
			org.slf4j
			slf4j-api
			1.6.6
		
		
			org.slf4j
			slf4j-log4j12
			1.6.6
		

		
		
			log4j
			log4j
			1.2.15
			
				
					com.sun.jmx
					jmxri
				
				
					com.sun.jdmk
					jmxtools
				
				
					javax.jms
					jms
				
			
		

		
		
			commons-codec
			commons-codec
			1.6
		
		
			com.xx.rtpc.shared.utils
			rtpc-crypt
			3.1.0
		

		
			c3p0
			c3p0
			0.9.1
		

		
			mysql
			mysql-connector-java
			5.1.4
		

		
			cglib
			cglib
			2.2
		
	

	
		demo
	


配置web.xml




    shiro-example

    
    
        contextConfigLocation
        
            /WEB-INF/dispatcher-servlet.xml
        
    

	
	
		org.springframework.web.context.request.RequestContextListener
	
	
		org.springframework.web.context.ContextLoaderListener
	

    
    
        shiroFilter
        org.springframework.web.filter.DelegatingFilterProxy
        true
        
            targetFilterLifecycle
            true
        
    

    
        shiroFilter
        /*
        REQUEST
    

   	
		dispatcher
		org.springframework.web.servlet.DispatcherServlet
		1
	
	
		dispatcher
		*.spring
	

	
		/home.spring
	


Spring Configure: dispatcher-servlet.xml

在src/main/webapp/WEB-INF下面新建Spring的配置文件,命名为dispatcher-servlet.xml.具体设定如下:




	

	

	
		
			
				
					
						text/html;charset=UTF-8
						text/plain;charset=UTF-8
					
				
			
			
				
					
						application/json
						text/json
					
				
			
		
	
	
	
    
    	
        
        
        
    
    
	
	
		
		
	


	
	
		
	

	
	
		
		
	

	
	
		
		
		
		
			
				/login.sping = anon
				/resources/** = anon
				/** = user
			
		
	

	
	

	
	
	
		
	
	
	
	
		
	

	
		
		
		
		
		
		
		
		
		
		
		
		
		
	
	
	
	
		
	

	
		
	
	
	
		
		
	


从配置文件可以看出我们要实现两个重要的模块,一个是CredentialsMatcher, 另外一个叫做Realm。CredentialsMatcher是用来验证密码的正确性,Realm则是来获取用户授权和认证的信息。


    
    	
        
        
        
    
    
	
	
		
		
	

首先来看一下自定义的Realm,

Shiro集成Spring_第2张图片

它继承了抽象类AuthorizingRealm,同时AuthorizingRealm又继承了抽象类AuthenticatingRealm,所以自定义的Realm中要实现两个抽象方法,一个是获取认证信息,另外一个是获取授权信息。具体如下:

public class XxDemoRealm extends AuthorizingRealm {

  UserService userService;
  @Override
  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    if (principals == null) {
      throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
    }

    String username = (String)principals.getPrimaryPrincipal();

    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    authorizationInfo.setRoles(userService.findRoles(username));
    authorizationInfo.setStringPermissions(userService.findPermissions(username));
    return authorizationInfo;
  }
  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
      throws AuthenticationException {
    UsernamePasswordToken upToken = (UsernamePasswordToken) token;
    String username = upToken.getUsername();

    if (username == null) {
      throw new AccountException("Null usernames are not allowed by this realm.");
    }

    String[] pwdSalt = userService.getUserPasswordAndSalt(username);
    if (pwdSalt == null) {
      throw new AccountException("No account found for user [" + username + "]");
    }
    
    return new SimpleAuthenticationInfo(username, pwdSalt[0].toCharArray(),
        ByteSource.Util.bytes(username + pwdSalt[1]), getName());
    
  }
  public void setUserService(UserService userService) {
    this.userService = userService;
  }
}

这里我们分别返回SimpleAuthenticationInfo和SimpleAuthorizationInfo,SimpleAuthenticationInfo是由用户名,登录密码,密码盐以及realm名称组成,而SimpleAuthorizationInfo继承与SimpleAuthenticationInfo,同时又包含了角色和权限的集合。

在spring的配置中我们定义自定义realm的时候指定了凭证匹配器:


	
	


凭证匹配器就是用来验证用户输入的帐号密码和数据库中的密码是否匹配。

public class DemoCredentialsMatcher extends HashedCredentialsMatcher {

  // 这里应该用cache来做, 不要用Map
  private static Map cache = new HashMap();

  private int retry = 5;

  @Override
  public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
    String username = (String) token.getPrincipal();
    AtomicInteger retryCount = cache.get(username);
    if (retryCount == null) {
      retryCount = new AtomicInteger(0);
      cache.put(username, retryCount);
    }
    if (retryCount.incrementAndGet() > retry) {
      throw new ExcessiveAttemptsException();
    }
    boolean matches = super.doCredentialsMatch(token, info);
    if (matches) {
      cache.remove(username);
    }
    return matches;
  }

  public void setRetry(int retry) {
    this.retry = retry;
  }

}

我们这里使用的是HashedCredentialsMatcher,另外添加了重试最大次数的机制,失败几次之后就不能登录了,解锁这里没有涉及到。

官方文档地址:http://shiro.apache.org/spring.html


未完待续。。。。。。


你可能感兴趣的:(Framework)