由于目前公司权限框架用的是shiro+token 机制,所以先花时间把shiro过了一遍,相比之前有了新的认识;
总的来说shiro作为单体应用权限框架其实已经很不错了,但由于cookie 原因,到了多体就显的有些无赖,所以目前公司可能也是基于这个加了token来解决问题
1.代码目录结构
有很多class没有用到,主要是因为用代码生成器,快捷,所以.......
2.数据库表
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_perms -- ---------------------------- DROP TABLE IF EXISTS `t_perms`; CREATE TABLE `t_perms` ( `id` int(6) NOT NULL AUTO_INCREMENT, `name` varchar(80) DEFAULT NULL, `url` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of t_perms -- ---------------------------- BEGIN; INSERT INTO `t_perms` VALUES (1, 'user:*:*', ''); INSERT INTO `t_perms` VALUES (2, 'product:*:01', NULL); INSERT INTO `t_perms` VALUES (3, 'order:*:*', NULL); COMMIT; -- ---------------------------- -- Table structure for t_role -- ---------------------------- DROP TABLE IF EXISTS `t_role`; CREATE TABLE `t_role` ( `id` int(6) NOT NULL AUTO_INCREMENT, `name` varchar(60) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of t_role -- ---------------------------- BEGIN; INSERT INTO `t_role` VALUES (1, 'admin'); INSERT INTO `t_role` VALUES (2, 'user'); INSERT INTO `t_role` VALUES (3, 'product'); COMMIT; -- ---------------------------- -- Table structure for t_role_perms -- ---------------------------- DROP TABLE IF EXISTS `t_role_perms`; CREATE TABLE `t_role_perms` ( `id` int(6) NOT NULL, `roleid` int(6) DEFAULT NULL, `permsid` int(6) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of t_role_perms -- ---------------------------- BEGIN; INSERT INTO `t_role_perms` VALUES (1, 1, 1); INSERT INTO `t_role_perms` VALUES (2, 1, 2); INSERT INTO `t_role_perms` VALUES (3, 2, 1); INSERT INTO `t_role_perms` VALUES (4, 3, 2); INSERT INTO `t_role_perms` VALUES (5, 1, 3); COMMIT; -- ---------------------------- -- Table structure for t_user -- ---------------------------- DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` int(6) NOT NULL AUTO_INCREMENT, `username` varchar(40) DEFAULT NULL, `password` varchar(40) DEFAULT NULL, `salt` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of t_user -- ---------------------------- BEGIN; INSERT INTO `t_user` VALUES (1, 'xiaochen', '24dce55acdcb3b6363c7eacd24e98cb7', '28qr0xu%'); INSERT INTO `t_user` VALUES (2, 'zhangsan', 'ca9f1c951ce2bfb5669f3723780487ff', 'IWd1)#or'); COMMIT; -- ---------------------------- -- Table structure for t_user_role -- ---------------------------- DROP TABLE IF EXISTS `t_user_role`; CREATE TABLE `t_user_role` ( `id` int(6) NOT NULL, `userid` int(6) DEFAULT NULL, `roleid` int(6) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of t_user_role -- ---------------------------- BEGIN; INSERT INTO `t_user_role` VALUES (1, 1, 1); INSERT INTO `t_user_role` VALUES (2, 2, 2); INSERT INTO `t_user_role` VALUES (3, 2, 3); COMMIT; SET FOREIGN_KEY_CHECKS = 1;
上述表中相应的数据也补充了,到时候可以直接测试
3. 项目pom
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--引入mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.5.3</version> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.41</version> </dependency> <!-- swagger2 配置 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.4.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.4.0</version> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.6</version> </dependency> <!--引入jsp解析依赖--> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency>
4.创建shiroFilter 负责拦截所以请求,这也是所以请求进入程序的入口+创建安全管理器 负责shiro实际调用的模块,shiro的认证和授权都是委托给WebSecurityManager去做的 +自定义Realm 主要负责应用和数据之间的衔接
package com.yb.demo_shiro.config; import com.yb.demo_shiro.shiro.CusRealm; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.realm.Realm; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; @Configuration public class ShiroConfig { //1.创建shiroFilter 负责拦截所以请求 @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean(); //2.给filter设置安全管理器 shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); //3.配置系统限制资源 //4.配置系统公共资源 Map<String,String> map=new HashMap<>(); map.put("/user/login","anon");//anon 设置为公共资源 放行资源放在下面 map.put("/user/register","anon");//anon 设置为公共资源 放行资源放在下面 map.put("/register.jsp","anon");//anon 设置为公共资源 放行资源放在下面 map.put("/user/getImage","anon"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); shiroFilterFactoryBean.setLoginUrl("/login.jsp"); return shiroFilterFactoryBean; } //2.创建安全管理器 @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){ DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager(); //2.给安全管理器设置Realm defaultWebSecurityManager.setRealm(realm); return defaultWebSecurityManager; } //3.创建自定义realm @Bean public Realm getRealm(){ CusRealm realm=new CusRealm(); //修改凭证校验匹配器 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); //设置加密算法为md5 credentialsMatcher.setHashAlgorithmName("MD5"); //设置散列次数 credentialsMatcher.setHashIterations(1024); realm.setCredentialsMatcher(credentialsMatcher); return realm; } }
会发现这3个是依次依赖的
ShiroFilterFactoryBean :