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

xiaoxiao2021-02-28  99

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

目前有二个主流权限管理的框架: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+"\"}"); }

转载请注明原文地址: https://www.6miu.com/read-31222.html

最新回复(0)