之前的文章中我们完成了基础框架的搭建,现在基本上所有的后台系统都逃不过权限管理这一块,这算是一个刚需了。现在我们来集成shiro来达到颗粒化权限管理,也就是从连接菜单到页面功能按钮,都进行权限都验证,从前端按钮的显示隐藏,到后台具体功能方法的权限验证。

首先要先设计好我们的数据库,先来看一张比较粗糙的数据库设计图:

具体的数据库设计代码,请查看:https://git.oschina.net/gzsjd/task/blob/master/sql/task.sql?dir=0&filepath=sql

下面我们开始根据之前的框架集成shiro

首先在pom.xml添加shiro的支持,先在properties中声明一下要倒入的版本:

<properties><shiro.version>1.3.2</shiro.version><commons-logging.version>1.2</commons-logging.version>
</properties>

然后在是dependency的添加:

<!-- shiro权限 --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-all</artifactId><version>${shiro.version}</version></dependency><!-- commons-logging --><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>${commons-logging.version}</version></dependency>

下面是shiro的配置跟spring配置放在同级目录spring-shiro.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:util="http://www.springframework.org/schema/util"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 缓存管理器 使用Ehcache实现 --><bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"><property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml" /></bean><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><!--认证管理器--><property name="realm" ref="shiroSecurityRealm" /><!-- 缓存管理器 --><property name="cacheManager" ref="cacheManager" /><!-- rememberMe管理器 --><property name="rememberMeManager" ref="rememberMeManager"/></bean><!-- 会话ID生成器 --><bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/><!-- 会话Cookie模板 --><bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"><constructor-arg value="sid"/><property name="httpOnly" value="true"/><property name="maxAge" value="-1"/></bean><bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">  <constructor-arg value="rememberMe"/>  <property name="httpOnly" value="true"/><property name="maxAge" value="2592000"/><!-- 30天 -->  </bean><!-- rememberMe管理器 --><bean id="rememberMeManager"class="org.apache.shiro.web.mgt.CookieRememberMeManager">  <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('7gzYfKjTASKdsai43ds==')}"/>  <property name="cookie" ref="rememberMeCookie"/></bean><!-- 会话DAO --><bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"><property name="activeSessionsCacheName" value="shiro-activeSessionCache"/><property name="sessionIdGenerator" ref="sessionIdGenerator"/></bean><!-- 会话验证调度器 --><bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler"><property name="sessionValidationInterval" value="3000000"/><property name="sessionManager" ref="sessionManager"/></bean><!-- 会话管理器 --><bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"><property name="globalSessionTimeout" value="3000000"/><property name="deleteInvalidSessions" value="true"/><property name="sessionValidationSchedulerEnabled" value="true"/><property name="sessionValidationScheduler" ref="sessionValidationScheduler"/><property name="sessionDAO" ref="sessionDAO"/><property name="sessionIdCookieEnabled" value="true"/><property name="sessionIdCookie" ref="sessionIdCookie"/></bean><bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">  <property name="rememberMeParam" value="rememberMe"/>  </bean><bean id="sysUserFilter" class="yfkj.gz.task.security.SysUserFilter"/><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><property name="securityManager" ref="securityManager"/><property name="loginUrl" value="/login.jsp"/><property name="successUrl" value="/page/main.action"/><property name="filters"><util:map><entry key="authc"><bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter"/></entry><entry key="sysUser" value-ref="sysUserFilter"/></util:map></property><property name="filterChainDefinitions"><value>/static/** = anon/login.jsp = anon/sysuser/login.action = anon/sysuser/register.action = anon/sysuser/getEMailCount.action = anon/sysuser/getUserNameCount.action = anon/sysuser/logout.action = logout/** = user,sysUser <!-- 表示访问该地址的用户是身份验证通过或RememberMe登录的都可以 --><!-- /** = authc  表示访问该地址用户必须身份验证通过--></value></property></bean><!-- Post processor that automatically invokes init() and destroy() methods --><bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/></beans>

上面的

/static/** = anon,/login.jsp = anon...这些等于anon的就是默认不做权限验证的,我们的登录,注册,静态资源等,不需要权限验证。

权限缓存的配置(如果不用缓存的话,每次请求都要去访问数据库查询权限)ehcache-shiro.xml:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="shirocache"><diskStore path="java.io.tmpdir/yfkj-shiro-ehcache"/><!-- 默认缓存 --><defaultCache maxElementsInMemory="1000" eternal="false"overflowToDisk="true" timeToIdleSeconds="300" timeToLiveSeconds="180"diskPersistent="false" diskExpiryThreadIntervalSeconds="120" /><!-- 登录记录缓存 --><cache name="passwordRetryCache"maxEntriesLocalHeap="2000"eternal="false"timeToIdleSeconds="3600"timeToLiveSeconds="0"overflowToDisk="false"statistics="true"></cache><!-- 授权缓存 --><cache name="authorizationCache"maxEntriesLocalHeap="2000"eternal="false"timeToIdleSeconds="3600"timeToLiveSeconds="0"overflowToDisk="false"statistics="true"></cache><!-- 认证缓存 --><cache name="authenticationCache"maxEntriesLocalHeap="2000"eternal="false"timeToIdleSeconds="3600"timeToLiveSeconds="0"overflowToDisk="false"statistics="true"></cache><cache name="shiro-activeSessionCache"maxEntriesLocalHeap="2000"eternal="false"timeToIdleSeconds="3600"timeToLiveSeconds="0"overflowToDisk="false"statistics="true"></cache><cache name="shiro-kickout-session"maxEntriesLocalHeap="2000"eternal="false"timeToIdleSeconds="3600"timeToLiveSeconds="0"overflowToDisk="false"statistics="true"></cache></ehcache>

自定义用户过滤类SysUserFilter:

import yfkj.gz.task.service.ISysUserService;import org.apache.shiro.web.filter.PathMatchingFilter;import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;/*** 自定义用户过滤器* @author 胡汉三**/
public class SysUserFilter extends PathMatchingFilter {@Resourceprivate ISysUserService sysUserService;@Overrideprotected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {//可以参考http://jinnianshilongnian.iteye.com/blog/2025656return true;}
}

权限认证类ShiroSecurityRealm:

import javax.annotation.Resource;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.Sha256CredentialsMatcher;
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 org.springframework.stereotype.Component;import yfkj.gz.task.dao.ISysUserDao;
import yfkj.gz.task.entity.SysRole;
import yfkj.gz.task.entity.SysUser;
import yfkj.gz.task.service.ISysUserService;/*** 权限认证* @author 胡汉三* @date   2017年1月19日 上午10:52:17*/
@SuppressWarnings("deprecation")
@Component
public class ShiroSecurityRealm extends AuthorizingRealm {@Resourceprivate ISysUserService userService;@Resourceprivate ISysUserDao sysUserDao;public ShiroSecurityRealm() {setName("ShiroSecurityRealm"); // This name must match the name in the SysUser class's getPrincipals() methodsetCredentialsMatcher(new Sha256CredentialsMatcher());}/*** 登录认证*/protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {UsernamePasswordToken token = (UsernamePasswordToken) authcToken;SysUser user = userService.getByProerties(new String[]{"loginAccount"}, new String[]{token.getUsername()},null);if (user != null) {return new SimpleAuthenticationInfo(user.getUserId(), user.getLoginPass(), getName());} else {return null;}}/*** 权限认证*/protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {Long userId = (Long) principals.fromRealm(getName()).iterator().next();SysUser user = userService.get(userId);if (user != null) {SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();for (SysRole role : user.getRoles()) {info.addRole(role.getRoleKey());info.addStringPermissions(role.getPermissions());}return info;} else {return null;}}}

在web.xml加入:

<!-- 加载spring配置文件 --><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring.xml,classpath:spring-hibernate.xml,classpath:spring-shiro.xml</param-value></context-param><!-- 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>

在登录方法中加上权限的登录(构造方法参数:登录账号,登录密码,记住我):

//存入sessionSubject subject = SecurityUtils.getSubject();//记得传入明文密码subject.login(new UsernamePasswordToken(userInfo.getLoginAccount(), user.getLoginPass(), rememberMe));

完整的登录方法:

/*** 用户登录* @param response* @param user* @throws IOException*/@RequestMapping(value = "/login", method = { RequestMethod.POST, RequestMethod.GET })public void login(SysUser user,boolean rememberMe) throws IOException{//用户登录SysUser userInfo = userService.getByProerties(new String[]{"loginAccount"}, new String[]{user.getLoginAccount()},null);if(userInfo==null){result.setMessage("用户名错误");super.writeJSON(result);return;}if(!userInfo.getLoginPass().equals(new Sha256Hash(user.getLoginPass()).toHex())){result.setMessage("密码错误");super.writeJSON(result);return;}//存入sessionSubject subject = SecurityUtils.getSubject();//记得传入明文密码subject.login(new UsernamePasswordToken(userInfo.getLoginAccount(), user.getLoginPass(), rememberMe));session.setAttribute(USER_SESSION, userInfo);result.setMessage("登录成功");result.setSuccess(true);super.writeJSON(result);}

数据库也设计好啦,该整合的也整合了,怎么来实现呢,这里先说一点点,详细的等下一篇说:

jsp页面引入page指令:

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

在要做验证的按钮上加上shiro标签的判断:

<shiro:hasPermission name="${ROLE_KEY}:role:role_add"><button id="btn_add" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增</button></shiro:hasPermission>

${ROLE_KEY}:role:role_add的意思就是:

${ROLE_KEY}角色

role是指菜单(页面)

role_add指的功能

联合起来就是,当前角色在role菜单(页面)中有没有role_add新增的功能,如果有就会显示,没有就不显示这个按钮啦。

在后台方法中验证:

在对应的方法中加入代码:

Subject subject = SecurityUtils.getSubject();
subject.checkPermission(getCurrentRoleKey()+":role:role_add");

如果没有通过checkPermission,则会直接返回错误,不执行下面的代码啦。

实体Base类BaseEntity:

import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;/*** 实体父类* @author 胡汉三* @date   2017年1月18日 上午11:03:11*/
public class BaseEntity implements Serializable{/*** */private static final long serialVersionUID = 3730369554400423966L;/*** 排序*/private Map<String, String> sortedConditions = new LinkedHashMap<String, String>();public Map<String, String> getSortedConditions() {return sortedConditions;}public void setSortedConditions(Map<String, String> sortedConditions) {this.sortedConditions = sortedConditions;}}

用户实体SysUser:

import java.util.HashSet;
import java.util.Set;import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.Table;import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;import yfkj.gz.support.BaseEntity;/*** 用户的实体类*/
@Entity
@Table(name = "sys_user")
public class SysUser extends BaseEntity{/*** */private static final long serialVersionUID = 2491111485758197830L;/**主键**/@Id@GeneratedValue@Column(name = "user_id")private Long userId;/**登录账号**/@Column(name = "login_account" ,length = 30 , unique = true )private String loginAccount;/**登录密码**/@Column(name = "login_pass" ,length = 65)private String loginPass;/**昵称**/@Column(name = "user_name" ,length = 20)private String userName;/**头像**/@Column(name = "user_head" ,length = 30)private String userHead;/**手机**/@Column(name = "user_phone" ,length = 20)private String userPhone;/**邮箱**/@Column(name = "user_email" ,length = 30)private String userEmail;/**性别**/@Column(name = "user_sex")private Integer userSex;/**生日**/@Column(name = "user_birthday" ,length = 30)private String userBirthday;/**注册时间**/@Column(name = "register_time" ,length = 30)private String registerTime;/**部门编码**/@Column(name = "department_key" ,length = 20)private String departmentKey;/**用户角色**/@ManyToMany(fetch = FetchType.EAGER)@JoinTable(name = "sys_user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = { @JoinColumn(name = "role_id") })@Cache(region = "all", usage = CacheConcurrencyStrategy.READ_WRITE)private Set<SysRole> roles = new HashSet<SysRole>();/**get/set**//**主键**/public Long getUserId(){return userId;}/**主键**/public void setUserId(Long userId){this.userId= userId;}/**登录账号**/public String getLoginAccount(){return loginAccount;}/**登录账号**/public void setLoginAccount(String loginAccount){this.loginAccount= loginAccount;}/**登录密码**/public String getLoginPass(){return loginPass;}/**登录密码**/public void setLoginPass(String loginPass){this.loginPass= loginPass;}/**昵称**/public String getUserName(){return userName;}/**昵称**/public void setUserName(String userName){this.userName= userName;}/**头像**/public String getUserHead(){return userHead;}/**头像**/public void setUserHead(String userHead){this.userHead= userHead;}/**手机**/public String getUserPhone(){return userPhone;}/**手机**/public void setUserPhone(String userPhone){this.userPhone= userPhone;}/**邮箱**/public String getUserEmail(){return userEmail;}/**邮箱**/public void setUserEmail(String userEmail){this.userEmail= userEmail;}/**性别**/public Integer getUserSex(){return userSex;}/**性别**/public void setUserSex(Integer userSex){this.userSex= userSex;}/**生日**/public String getUserBirthday(){return userBirthday;}/**生日**/public void setUserBirthday(String userBirthday){this.userBirthday= userBirthday;}/**注册时间**/public String getRegisterTime(){return registerTime;}/**注册时间**/public void setRegisterTime(String registerTime){this.registerTime= registerTime;}public Set<SysRole> getRoles() {return roles;}public void setRoles(Set<SysRole> roles) {this.roles = roles;}}

角色实体SysRole:

import java.util.Set;import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Table;import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;import yfkj.gz.support.BaseEntity;/*** 角色的实体类*/
@Entity
@Table(name = "sys_role")
@Cache(region = "all", usage = CacheConcurrencyStrategy.READ_WRITE)
public class SysRole extends BaseEntity{// 各个字段的含义请查阅文档的数据库结构部分private static final long serialVersionUID = 6019103858711599150L;@Id@GeneratedValue@Column(name = "role_id")private Long roleId;@Column(name = "role_key", length = 40, nullable = false, unique = true)private String roleKey;@Column(name = "role_value", length = 40, nullable = false)private String roleValue;@Column(name = "create_time", length = 30)private String createTime;@Column(name = "description", length = 200)private String description;@ElementCollection@JoinTable(name = "sys_role_permission", joinColumns = { @JoinColumn(name = "role_id") })@Cache(region = "all", usage = CacheConcurrencyStrategy.READ_WRITE)private Set<String> permissions;@Column(name="company_id")private Long companyId;public SysRole() {}public Long getRoleId() {return roleId;}public void setRoleId(Long roleId) {this.roleId = roleId;}public String getRoleKey() {return roleKey;}public void setRoleKey(String roleKey) {this.roleKey = roleKey;}public String getRoleValue() {return roleValue;}public void setRoleValue(String roleValue) {this.roleValue = roleValue;}public String getCreateTime() {return createTime;}public void setCreateTime(String createTime) {this.createTime = createTime;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public Set<String> getPermissions() {return permissions;}public void setPermissions(Set<String> permissions) {this.permissions = permissions;}public Long getCompanyId() {return companyId;}public void setCompanyId(Long companyId) {this.companyId = companyId;}}

项目结构图:

源码地址: https://git.oschina.net/gzsjd/task

spring整合shiro权限管理与数据库设计相关推荐

  1. 39 Spring Boot Shiro权限管理【从零开始学Spring Boot】

    [视频 & 交流平台] à SpringBoot视频 http://study.163.com/course/introduction.htm?courseId=1004329008& ...

  2. (39.3) Spring Boot Shiro权限管理【从零开始学Spring Boot】

    在学习此小节之前您可能还需要学习: (39.1) Spring Boot Shiro权限管理[从零开始学Spring Boot] http://412887952-qq-com.iteye.com/b ...

  3. Spring Boot Shiro 权限管理

    Spring Boot Shiro 权限管理 标签: springshiro 2016-01-14 23:44 94587人阅读 评论(60) 收藏 举报 本来是打算接着写关于数据库方面,集成MyBa ...

  4. Spring Boot Shiro权限管理

    转:http://412887952-qq-com.iteye.com/blog/2299777 (1). Shiro简单介绍 Shiro是Apache下的一个开源项目,我们称之为Apache Shi ...

  5. Spring +mybatisplus+shiro权限管理集成整合

    一.Apache Shiro是一个功能强大.灵活的,开源的安全框架.它可以干净利落地处理身份验证.授权.企业会话管理和加密. Shiro能做什么呢? 验证用户身份 用户访问权限控制,比如:1.判断用户 ...

  6. Spring boot整合shiro权限管理

    apache shiro: https://shiro.apache.org/ Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.使用Shiro的易于理 ...

  7. Spring Boot Shiro权限管理--自定义 FormAuthenticationFilter验证码整合

    思路 shiro使用FormAuthenticationFilter进行表单认证,验证校验的功能应该加在FormAuthenticationFilter中,在认证之前进行验证码校验. 需要写FormA ...

  8. SSM集成shiro权限管理

    这几天在学习了shiro权限管理框架,在刚开始的时候学的时候因为这个配置问题困扰了我很长时间,所以在这篇文章我整合了自己用SSM搭建shiro权限框架的过程. 1.配置 1.1jar包 在项目配置开始 ...

  9. MySQL学习笔记8:权限管理、数据库备份与设计

    1.前言 学习视频源自:[狂神说Java]MySQL最新教程通俗易懂 B站视频链接:https://www.bilibili.com/video/BV1NJ411J79W [狂神说Java]MySQL ...

最新文章

  1. Disruptor官方文档实现
  2. Kubernetes安装之证书验证
  3. MindSpore:不用摘口罩也知道你是谁
  4. (转载)测试理论面试题
  5. oracle 偶尔登录超时,OracleClient,间歇性连接问题:应用程序挂起在OracleConnection.Open()上,没有超时,没有引发异常...
  6. mysql 左连接写法_mysql左连接复杂正确写法
  7. 社交规则:饭后抢着买单到底是客气还是客套?大多并不是真心的
  8. 论文阅读:Negative Lexically Constrained Decoding for Paraphrase Generation
  9. 无法启动 Windows Event Log vpdn 无法启动 附带无法启动MYSQL服务”1067 进程意外终止”
  10. 你想制作一款属于自己的游戏吗?
  11. 对自动驾驶仿真软件研发方向的看法
  12. 计算机c语言lms算法,lms算法(毕业论文).doc
  13. 游戏思考系列03:游戏匹配机制(MMR、ELO、trueskill2、皇家战争、Glicko等,详细讲ELO,其他的简略)
  14. 新增A股热门概念行情—股票数据远程下载服务升级
  15. 商务网站建设与维护【14】
  16. 计算机软件公司用ps是,[计算机软件及应用]PS培训.ppt
  17. Raspberry Pi Pico SDK开发-时钟管理
  18. 数据恢复问题分析及注意事项
  19. 服务器租用托管如何选择合适的线路和带宽
  20. mysql sql语句生成日历表

热门文章

  1. Android中的阿里云仓库
  2. java String、Json对象与byte数组转换
  3. 写一个简单的python调用接口(API)
  4. Metasploit进行渗透测试的常用流程【入门】
  5. 资格考试_第四章_证券投资基金的监督
  6. “5G+4G”聚合路由器多链路图传技术巩固安防监控行业
  7. 椭圆曲线密码算术(ECC)原理
  8. 7-12 打印倒直角三角形图案
  9. 「译」Web安全快速入门
  10. 光标快速移动到文档尾部_把光标移动到文件尾部的快捷键是什么呢?