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

来源:互联网 发布:电子商务网络推广 编辑:程序博客网 时间:2024/06/08 18:16

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

目前有二个主流权限管理的框架: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;/** * 授权 */@Overrideprotected 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;  }/** * 认证 */@Overrideprotected 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()); }@Overridepublic 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.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsdhttp://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(){//移除sessionSubject 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" onclick="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" onclick="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" onclick="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+"\"}");}







0 0