web开发中spring集成shiro进行权限管理

权限管理是一个系统不可缺少的一部分,也是比较复杂的一部分。

目前有二个主流权限管理的框架:shiro 和spring security ,以下讲解spring如何集成apache shiro

第一步:导入shiro的jar包

shiro-aspectj-1.2.2.jar
shiro-cas-1.2.2.jar
shiro-core-1.2.2.jar
shiro-ehcache-1.2.2.jar
shiro-guice-1.2.2.jar
shiro-quartz-1.2.2.jar
shiro-spring-1.2.2.jar
shiro-tools-hasher-1.2.2-cli.jar
shiro-web-1.2.2.jar

第二步:编写自己的Realm实现类:

package com.bs.common.shiro.realm;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Resource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import com.bs.exception.BsException;
import com.bs.exception.BsExceptionCode;
import com.bs.system.po.BookUserInfo;
import com.bs.system.service.IBookUserService;

public class MyRealm extends AuthorizingRealm {

	@Resource(name="bookUserService")
	private IBookUserService bookUserService;
	
	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
		//arg0.getPrimaryPrincipal(): 实际上是在认证时返回的 SimpleAuthenticationInfo 的第一个参数!  
      //  Object principal = arg0.getPrimaryPrincipal();  
      //  ShiroUser user = (ShiroUser) principal;  
        ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getSession().getAttribute("userObj");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(user.getRoles());
        info.setStringPermissions(user.getPermissions());
        return info;  
	}

	/**
	 * 认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken arg0) throws AuthenticationException {
		//强转为UsernamePasswordToken类型  
        UsernamePasswordToken token=(UsernamePasswordToken)arg0;   
          
        //获取用户名和密码(密码要转为字符串类型)  
        String username = token.getUsername();  
        String password = new String(token.getPassword());  
          
        //测试一下,看是否得到了用户名和密码  
         System.out.println("username: " + username + ", password: " + password); 
         BookUserInfo bookUserInfo = null;
         try {
			 bookUserInfo = bookUserService.loginService(username, password);
			 if(bookUserInfo==null){
				 throw new IncorrectCredentialsException("密码错误"); 
			 }
		} catch(BsException bs){
			if(BsExceptionCode.ERROR_CODE_NO_DATA==bs.getErrorCode()){
				throw new UnknownAccountException("账户不存在,请联系管理员!");
			}
		}
         //利用新建的类来创建对象  
         ShiroUser user=new ShiroUser();  
         user.setUsername(username); //将页面中的username值设置进去
         //模拟设置权限部分
        //实际项目中:从数据库根据用户名去查询其角色和权限
        if("admin".equals(username)){  
            //如果用户名为:admin,则为其增加2个角色 admin和user  
        	//这里是模拟设置角色
            user.getRoles().add("admin");  
            user.getRoles().add("user");  
            Set<String> permissions = new HashSet<String>();
            //这里是模拟设置权限
            permissions.add("book:add");
            permissions.add("book:create");
            user.setPermissions(permissions);
        }else {  
            //如果用户名不为admin,则为其增加user角色  
            user.getRoles().add("user");  
        }  
        SecurityUtils.getSubject().getSession().setAttribute("userObj", user);
        return new SimpleAuthenticationInfo(username, password,getName()); 
	}
	
	@Override
	public String getName() {
		return "myRealm";
	}
	
	//新建一个类定义用户角色和权限  
    class ShiroUser implements Serializable{  
        private static final long serialVersionUID = 1L;  
        private String username;  
        private Set<String> roles= new HashSet<String>();  
        private Set<String> permissions = new HashSet<String>(); 
        public String getUsername() {  
            return username;  
        }  
        public void setUsername(String username) {  
            this.username = username;  
        }  
        public Set<String> getRoles() {  
            return roles;  
        }  
        public void setRoles(Set<String> roles) {  
            this.roles = roles;  
        }
		public Set<String> getPermissions() {
			return permissions;
		}
		public void setPermissions(Set<String> permissions) {
			this.permissions = permissions;
		}  
        
    }  

}


第三步:在src目录下新建applicationContext-shiro.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:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
    <!--2.配置CacheManager实例:管理Shiro相关缓存操作  -->  
   <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">   
        <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"></property>  
    </bean>   
      
    <!--3.配置realm实例,实际的认证和授权都是由Realm实例来完成的!  -->  
    <bean id="myRealm" class="com.bs.common.shiro.realm.MyRealm"></bean>  
  
    <!-- 4.配置 SecurityManager 实例. SecurityManager 是 Shiro 最核心的组件 -->  
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
        <property name="cacheManager" ref="cacheManager"/>  
        <property name="realm" ref="myRealm"/>  
    </bean>  
      
    <!--5.配置bean的后置处理器来自动调用Shiro中的bean的init和destroy方法。  -->  
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>  
      
      
    <!--6.配置使shiro注解起作用的bean,需要放在 lifecycleBeanPostProcessor后面 -->  
    <aop:config proxy-target-class="true"></aop:config>  
    <!-- <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"></bean>       -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">  
        <property name="securityManager" ref="securityManager"></property>  
    </bean>  
      
    <!--  
        7.配置哪些页面需要被拦截,以及访问这些页面所需的权限 。  
        该bean中的id 属性值必须和 web.xml 文件中配置的 filter 的 filter-name 值一致  
    -->  
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
        <property name="securityManager" ref="securityManager"></property>  
      
        <!--①配置登陆页面  -->  
        <property name="loginUrl" value="/index.jsp"></property>  
        <property name="successUrl" value="/admin.jsp"></property>  
        <property name="unauthorizedUrl" value="/index.jsp"></property>  
       <!--  <property name="filters">
            <util:map>
                <entry key="authc">
                    <bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter"/>
                </entry>
        	</util:map>
        </property> -->
        <!--②配置需要被拦截的资源 以及访问权限 -->  
        <property name="filterChainDefinitions">  
            <value>  
                <!-- anon: 表示匿名的, 即任何人都可以访问 --> 
                /add.jsp=anon
                /images/**=anon
                /js/**=anon
                /skin/**=anon
                /upload/**=anon 
                /index.jsp=anon
                /login.jsp=anon  
                /user/**=anon 
                /system/**=anon 
                /book/**=anon 
                /login=anon  
                /logout=logout 
                <!--③设置访问具体资源的权限  -->  
                /admin.jsp=roles[admin]  
                /user.jsp=roles[user]  
                <!-- authc 表示必须经过认证之后才可以访问的页面 -->  
                /**=authc  
            </value>  
        </property>  
    </bean>  
	
	</beans>
第四步:在src目录新建ehcache-shiro.xml配置文件,内容如下:

<ehcache>  
    <diskStore path="java.io.tmpdir/shiro-spring-sample"/>  
    <defaultCache  
            maxElementsInMemory="10000"  
            eternal="false"  
            timeToIdleSeconds="120"  
            timeToLiveSeconds="120"  
            overflowToDisk="false"  
            diskPersistent="false"  
            diskExpiryThreadIntervalSeconds="120"  
            />  
  
    <cache name="shiro-activeSessionCache"  
           maxElementsInMemory="10000"  
           eternal="true"  
           overflowToDisk="true"  
           diskPersistent="true"  
           diskExpiryThreadIntervalSeconds="600"/>  
  
    <cache name="org.apache.shiro.realm.SimpleAccountRealm.authorization"  
           maxElementsInMemory="100"  
           eternal="false"  
           timeToLiveSeconds="600"  
           overflowToDisk="false"/>  
</ehcache>  
第五步:修改web.xml配置文件:

<context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:applicationContext.xml,classpath:applicationContext-shiro.xml</param-value>
  </context-param>
配置shiro过滤器:需要配置在struts2或者springmvc框架的拦截配置之前

 <!--配置shiro过滤器  -->  
   <filter>  
        <filter-name>shiroFilter</filter-name>  
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
        <init-param>  
            <param-name>targetFilterLifecycle</param-name>  
            <param-value>true</param-value>  
        </init-param>   
    </filter>  
    <filter-mapping>  
        <filter-name>shiroFilter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  

至此,spring集成shiro配置完毕。

编写登陆的处理方法:

public String login(){
		//数据验证
		if(ObjectFormatUtil.isNotNull(username) && ObjectFormatUtil.isNotNull(password)){
			try {
				//1.获取当前的用户  
			     Subject currentUser = SecurityUtils.getSubject();  
			        //2.把登录信息封装为一个 UsernamePasswordToken 对象  
			     UsernamePasswordToken token=new UsernamePasswordToken(this.username,this.password);  
			     currentUser.login(token);  
			} catch (UnknownAccountException uae) {  
                System.out.println("用户名不存在: " + uae);  
                return "input";  
            } catch (IncorrectCredentialsException ice) {  
                System.out.println("用户名存在,但密码和用户名不匹配: " + ice);  
                return "input";  
            } catch (LockedAccountException lae) {  
                System.out.println("用户被锁定: " + lae);  
                return "input";  
            } catch (AuthenticationException ae) {  
                System.out.println("其他异常: " + ae);  
                return "input";  
            }  
		}else{
			message = "用户名或密码不能为空";
		}
		return "main";
	}

编程退出登录方法:

public String loginout(){
		//移除session
		Subject currentUser = SecurityUtils.getSubject(); 
		currentUser.logout();
		return "loginPage";
	}

shiro标签的使用:

以下配置表示:拥有admin角色的用户可以显示图书管理和系统管理菜单

<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %>
	<shiro:hasRole name="admin">
			<dd><div class='item' id='item8' onMouseMove="mv(this,'m',8);" onMouseOut="mv(this,'o',8);"><a href="${ctx}/jsp/main/user/bookmenu.jsp" οnclick="changeSel(8)" target="menu">图书管理</a></div></dd>
			<dd><div class='item' id='item4' onMouseMove="mv(this,'m',4);" onMouseOut="mv(this,'o',4);"><a href="${ctx}/jsp/main/user/usermenu.jsp" οnclick="changeSel(4)" target="menu">系统管理</a></div></dd>
		</shiro:hasRole>

使用注解配置action类中方法访问的权限:

以下注解表示拥有admin角色的用户可以访问该方法:

	/**
	 * 添加分馆
	 * @return
	 */
	@RequiresRoles({"admin"})
	public String doAdd(){
		try {			 
			if(!ObjectFormatUtil.isNotNull(bookLib.getLibname())){
				message = "输入的信息有误";
				return MESSAGE;
			}
			if(null==bookLibService.save(bookLib)){
				message = "保存信息失败";
				return MESSAGE;
			}
			return list();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "message";
	}

当没有权限访问以下action类的方法时,会抛出org.apache.shiro.authz.UnauthorizedException异常,我们需要在struts2中进行该异常处理:

	<global-results>
			<result name="permissionmessage">/jsp/common/permissionmessage.jsp</result>
	</global-results>
	<global-exception-mappings>
           <exception-mapping result="permissionmessage" exception="org.apache.shiro.authz.UnauthorizedException">
              </exception-mapping>
       </global-exception-mappings>

如果使用ajax异步访问我们action类中方法时,如果没有权限,我们该怎样处理了?

如:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
<c:set var="ctx" value="${pageContext.request.contextPath}"></c:set>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">  
    <title>add page</title>
	<script type="text/javascript" src="${ctx}/js/jquery-2.1.1.min.js"></script>
	<script type="text/javascript">
		function add(){
			$.ajax({
				url:"${ctx}/system/testBookLib.action",
				type:"post",
				data:{"bookLib.libname":$("#libname").val()},
				dataType:"json",
				success:function(data){
					if(data.result){
						alert("添加成功");
					}else{
						alert(data.message);
					}
				}
			});
		}
	</script>
  </head>
  <body>
    图书馆名称:<input type="text" name="libname" id="libname"/> <br>
    <input type="button" value="添加" id="btn_add" οnclick="add()"/>
  </body>
</html>

1、我们可以使用以下方式:

public void test1(){
		boolean result = false;	
		Subject subject = SecurityUtils.getSubject(); 
		if(subject.hasRole("admin")){
			//1验证数据
			if(!ObjectFormatUtil.isNotNull(bookLib.getLibname())){
				message = "输入的信息有误";
			}
			//2验证图书名称是否已存在  如果已存在  则添加失败  给出提示  反正添加成功
			if(bookLibService.isExistBooklibName(bookLib.getLibname())){
				if(null==bookLibService.save(bookLib)){
					message = "保存信息失败";
				}else{
					result = true;
				}
			}else{
				message = "图书名称已存在";
			}
		}else{
			message ="无权访问";
		}		
		outJsonString(response, "{\"result\":"+result+",\"message\":\""+message+"\"}");
	}				







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值