Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
主要功能
三个核心组件:Subject、SecurityManager 和 Realms.
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
1、简单了解Shiro的API
添加相关依赖pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--shiro核心类库--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.3</version> </dependency> <!-- logback 依赖包--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
编写shiro配置文件,在resources目录下编写shiro配置文件,shiro.ini
#用户名=密码,角色1,角色2...,角色n [users] root = secret, admin guest = guest, guest test = 123456, role1, role2 # ----------------------------------------------------------------------------- # Roles with assigned permissions # roleName = perm1, perm2, ..., permN # 角色名=权限1,权限2...权限n # ----------------------------------------------------------------------------- [roles] admin = * guest = guest role1=perm1,perm2 role2=perm3
测试类
package com.example.demo.shiro; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; /** * 路径:com.example.demo.shiro * 类名: * 功能:《用一句描述一下》 * 备注: * 创建人:typ * 创建时间:2018/10/8 17:50 * 修改人: * 修改备注: * 修改时间: */ @Slf4j public class ShiroTest { public static void main(String[] args) { //创建 SecurityManager Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); //解析配置文件,并返回一些 SecurityManager SecurityManager securityManager = factory.getInstance(); //将SecurityManager SecurityUtils.setSecurityManager(securityManager); //安全操作,Subject Subject currentUser = SecurityUtils.getSubject(); //测试在应用的当前会话中设置的属性 Session session = currentUser.getSession(); //放进去一个key session.setAttribute("someKey", "aValue"); //根据key获取value String value = (String) session.getAttribute("someKey"); //比较拿到的值和原来的值是否一致 if ("aValue".equals(value)) { log.info("检索到正确的值[" + value + "]"); } //尝试进行登录用户,如果登录失败了,我们进行一些处理 if (!currentUser.isAuthenticated()) { //如果用户没有登录过 UsernamePasswordToken token = new UsernamePasswordToken("test", "123456"); //是否记住用户 token.setRememberMe(true); try { currentUser.login(token); //当我们获登录用户之后 log.info("用户 [" + currentUser.getPrincipal() + "] 登陆成功"); // 查看用户是否有指定的角色 if (currentUser.hasRole("admin")) { log.info("您有admin角色"); } else { log.info("您没有admin角色"); } if (currentUser.hasRole("role1")) { log.info("您有role1角色"); } else { log.info("您没有role1角色"); } // 查看用户是否有某个权限 if (currentUser.isPermitted("perm1")) { log.info("您有perm1权限"); } else { log.info("您没有perm1权限"); } if (currentUser.isPermitted("guest")) { log.info("您有guest权限"); } else { log.info("您没有guest权限"); } //退出 currentUser.logout(); } catch (UnknownAccountException uae) { log.info(token.getPrincipal() + "账户不存在"); } catch (IncorrectCredentialsException ice) { log.info(token.getPrincipal() + "密码不正确"); } catch (LockedAccountException lae) { log.info(token.getPrincipal() + "用户被锁定了 "); } catch (AuthenticationException ae) { //无法判断是什么错了 log.info(ae.getMessage()); } } } }
运行程序,查看结果如下:
21:41:25.606 [main] DEBUG org.apache.shiro.subject.support.DefaultSubjectContext - No SecurityManager available in subject context map. Falling back to SecurityUtils.getSecurityManager() lookup. 21:41:25.610 [main] INFO com.example.demo.shiro.ShiroTest - 用户 [test] 登陆成功 21:41:25.610 [main] INFO com.example.demo.shiro.ShiroTest - 您没有admin角色 21:41:25.610 [main] INFO com.example.demo.shiro.ShiroTest - 您有role1角色 21:41:25.610 [main] INFO com.example.demo.shiro.ShiroTest - 您有perm1权限 21:41:25.634 [main] INFO com.example.demo.shiro.ShiroTest - 您没有guest权限 21:41:25.634 [main] DEBUG org.apache.shiro.mgt.DefaultSecurityManager - Logging out subject with primary principal test
2、Shiro+MySQL动态权限验证
数据库设计:
用户表(SHIRO_USER)、用户角色表(SHIRO_USER_ROLE)、角色权限表(SHIRO_ROLE_PERMISSION)
SQL如下:
# Host: 127.0.0.1 (Version 5.7.21) # Date: 2018-10-08 22:26:32 # Generator: MySQL-Front 6.0 (Build 2.20) # # Structure for table "shiro_user" # DROP TABLE IF EXISTS `shiro_user`; CREATE TABLE `shiro_user` ( `id` varchar(32) DEFAULT NULL, `user_name` varchar(50) DEFAULT NULL, `password` varchar(32) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; # # Data for table "shiro_user" # INSERT INTO `shiro_user` VALUES ('1','[email protected]','123456'); # # Structure for table "shiro_user_role" # DROP TABLE IF EXISTS `shiro_user_role`; CREATE TABLE `shiro_user_role` ( `id` varchar(32) DEFAULT NULL, `role_name` varchar(50) DEFAULT NULL, `user_name` varchar(50) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; # # Data for table "shiro_user_role" # INSERT INTO `shiro_user_role` VALUES ('1','admin','[email protected]'),('2','test','[email protected]'); # # Structure for table "shiro_role_permission" # DROP TABLE IF EXISTS `shiro_role_permission`; CREATE TABLE `shiro_role_permission` ( `id` varchar(32) DEFAULT NULL, `role_name` varchar(50) DEFAULT NULL, `perm_name` varchar(50) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; # # Data for table "shiro_role_permission" # INSERT INTO `shiro_role_permission` VALUES ('1','admin','perm1'),('2','test','guest');
添加数据库相关的依赖,pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--shiro核心类库--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.3</version> </dependency> <!-- logback 依赖包--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
编写shiro配置文件,在resources目录下编写shiro配置文件,shiro-mysql.ini
[main] dataSource=com.alibaba.druid.pool.DruidDataSource dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql://127.0.0.1:3306/mc_config dataSource.username=root dataSource.password=admin jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm #是否检查权限 jdbcRealm.permissionsLookupEnabled = true jdbcRealm.dataSource=$dataSource #重写sql语句 #根据用户名查询出密码 jdbcRealm.authenticationQuery = select PASSWORD from SHIRO_USER where USER_NAME = ? #根据用户名查询出角色 jdbcRealm.userRolesQuery = select ROLE_NAME from SHIRO_USER_ROLE where USER_NAME = ? #根据角色名查询出权限 jdbcRealm.permissionsQuery = select PERM_NAME from SHIRO_ROLE_PERMISSION WHERE ROLE_NAME = ? securityManager.realms=$jdbcRealm
测试类
package com.example.demo.shiro; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.apache.shiro.mgt.SecurityManager; /** * 路径:com.example.demo.shiro * 类名: * 功能:Shiro+MySQL动态权限验证 * 备注: * 创建人:typ * 创建时间:2018/10/8 21:57 * 修改人: * 修改备注: * 修改时间: */ @Slf4j public class ShiroMysqlTest { public static void main(String[] args) { Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-mysql.ini"); SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); Subject currentUser = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("[email protected]", "123456"); //是否记住用户 token.setRememberMe(true); try { currentUser.login(token); //当我们获登录用户之后 log.info("用户 [" + currentUser.getPrincipal() + "] 登陆成功"); //查看用户是否有角色 if (currentUser.hasRole("admin")) { log.info("您有admin角色"); } else { log.info("您没有admin角色"); } if (currentUser.hasRole("test")) { log.info("您有test角色"); } else { log.info("您没有test角色"); } // 查看用户是否有某个权限 if (currentUser.isPermitted("perm1")) { log.info("您有perm1权限"); } else { log.info("您没有perm1权限"); } if (currentUser.isPermitted("guest")) { log.info("您有guest权限"); } else { log.info("您没有guest权限"); } //退出 currentUser.logout(); } catch (UnknownAccountException uae) { log.info(token.getPrincipal() + "账户不存在"); } catch (IncorrectCredentialsException ice) { log.info(token.getPrincipal() + "密码不正确"); } catch (LockedAccountException lae) { log.info(token.getPrincipal() + "用户被锁定了 "); } catch (AuthenticationException ae) { //无法判断是什么错了 log.info(ae.getMessage()); } } }
运行程序,查看结果如下:
21:48:00.094 [main] INFO com.example.demo.shiro.ShiroMysqlTest - 用户 [[email protected]] 登陆成功 21:48:00.098 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No authorizationCache instance set. Checking for a cacheManager... 21:48:00.098 [main] INFO org.apache.shiro.realm.AuthorizingRealm - No cache or cacheManager properties have been set. Authorization cache cannot be obtained. 21:48:00.102 [main] INFO com.example.demo.shiro.ShiroMysqlTest - 您有admin角色 21:48:00.102 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No authorizationCache instance set. Checking for a cacheManager... 21:48:00.102 [main] INFO org.apache.shiro.realm.AuthorizingRealm - No cache or cacheManager properties have been set. Authorization cache cannot be obtained. 21:48:00.110 [main] INFO com.example.demo.shiro.ShiroMysqlTest - 您有test角色 21:48:00.110 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No authorizationCache instance set. Checking for a cacheManager... 21:48:00.110 [main] INFO org.apache.shiro.realm.AuthorizingRealm - No cache or cacheManager properties have been set. Authorization cache cannot be obtained. 21:48:00.114 [main] INFO com.example.demo.shiro.ShiroMysqlTest - 您有perm1权限 21:48:00.114 [main] DEBUG org.apache.shiro.realm.AuthorizingRealm - No authorizationCache instance set. Checking for a cacheManager... 21:48:00.114 [main] INFO org.apache.shiro.realm.AuthorizingRealm - No cache or cacheManager properties have been set. Authorization cache cannot be obtained. 21:48:00.122 [main] INFO com.example.demo.shiro.ShiroMysqlTest - 您有guest权限 21:48:00.122 [main] DEBUG org.apache.shiro.mgt.DefaultSecurityManager - Logging out subject with primary principal [email protected]
3. SpringBoot整合mybatis、shiro、redis实现基于数据库动态权限管理系统实例
。。。。。。