6.1 整合思路

6.2 配置环境
- 创建项目
- 引入依赖
<!--引入shiro整合Springboot依赖--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.5.3</version> </dependency> <!--引入扩展依赖--> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> - 页面中引入命名空间
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> ...... - 常见权限控制标签使用
<!-- 验证当前用户是否为“访客”,即未认证(包含未记住)的用户。 --> <p shiro:guest="">Please <a href="login.html">login</a></p> <!-- 认证通过或已记住的用户。 --> <p shiro:user=""> Welcome back John! Not John? Click <a href="login.html">here</a> to login. </p> <!-- 已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在。 --> <p shiro:authenticated=""> Hello, <span shiro:principal=""></span>, how are you today? </p> <a shiro:authenticated="" href="updateAccount.html">Update your contact information</a> <!-- 输出当前用户信息,通常为登录帐号信息。 --> <p>Hello, <shiro:principal/>, how are you today?</p> <!-- 未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户。 --> <p shiro:notAuthenticated=""> Please <a href="login.html">login</a> in order to update your credit card information. </p> <!-- 验证当前用户是否属于该角色。 --> <a shiro:hasRole="admin" href="admin.html">Administer the system</a><!-- 拥有该角色 --> <!-- 与hasRole标签逻辑相反,当用户不属于该角色时验证通过。 --> <p shiro:lacksRole="developer"><!-- 没有该角色 --> Sorry, you are not allowed to developer the system. </p> <!-- 验证当前用户是否属于以下所有角色。 --> <p shiro:hasAllRoles="developer, 2"><!-- 角色与判断 --> You are a developer and a admin. </p> <!-- 验证当前用户是否属于以下任意一个角色。 --> <p shiro:hasAnyRoles="admin, vip, developer,1"><!-- 角色或判断 --> You are a admin, vip, or developer. </p> <!--验证当前用户是否拥有指定权限。 --> <a shiro:hasPermission="userInfo:add" href="createUser.html">添加用户</a><!-- 拥有权限 --> <!-- 与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。 --> <p shiro:lacksPermission="userInfo:del"><!-- 没有权限 --> Sorry, you are not allowed to delete user accounts. </p> <!-- 验证当前用户是否拥有以下所有角色。 --> <p shiro:hasAllPermissions="userInfo:view, userInfo:add"><!-- 权限与判断 --> You can see or add users. </p> <!-- 验证当前用户是否拥有以下任意一个权限。 --> <p shiro:hasAnyPermissions="userInfo:view, userInfo:del"><!-- 权限或判断 --> You can see or delete users. </p> <a shiro:hasPermission="pp" href="createUser.html">Create a new User</a> - 加入shrio方言配置
页面标签不起作用一定要记住加入方言处理
@Bean(name = "shiroDialect") public ShiroDialect shiroDialect(){ return new ShiroDialect(); }
6.3 整合配置类
用来整合shiro框架相关的配置类
package com.chif.shiro.config; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import com.chif.shiro.config.cache.RedisCacheManager; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig {
@Bean(name = "shiroDialect") public ShiroDialect shiroDialect(){
return new ShiroDialect(); } //1.创建shiroFilter 负责拦截所有请求 //ShiroFilterFactoryBean 3 @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //设置安全管理器 (自动配置) bean.setSecurityManager(defaultWebSecurityManager); //配置系统受限资源 /* anon:无需认证就可以访问 outhc:必须认证了才能访问 user:必须拥有记住我功能才能使用 perms:拥有对某个资源的权限才能访问 role:拥有某个角色权限才能访问 */ Map<String, String> filterMap = new LinkedHashMap<>(); //授权,正常的情况下,没有授权会跳转到未授权的页面 filterMap.put("/user/add","perms[user:add]"); filterMap.put("/user/*","authc");//authc 请求这个资源需要认证和授权 // filterMap.put("/*","authc");//authc 请求这个资源需要认证和授权 filterMap.put("/login","anon");//anon 设置为公共资源 filterMap.put("/getImage","anon");//验证码 设置为公共资源 filterMap.put("/register","anon");//anon 设置为公共资源 //添加shiro的内置过滤器 bean.setFilterChainDefinitionMap(filterMap); //配置系统公共资源 //设置默认认证界面 //默认认证界面路径就是 login.xxx bean.setLoginUrl("/toLogin"); //设置未授权页面 bean.setUnauthorizedUrl("/noauth"); return bean; } //2.创建安全管理器 //DefaultWebSecurityManager 2 @Bean(name = "SecurityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(); //给安全管理器关联UserRealm securityManager.setRealm(userRealm); return securityManager; } //创建 realm 对象 ,需要自定义类 1 @Bean(name = "userRealm") public UserRealm userRealm(){
UserRealm userRealm = new UserRealm(); //修改凭证校验匹配器 HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); //设置加密算法为md5 hashedCredentialsMatcher.setHashAlgorithmName("Md5"); //设置散列的次数 hashedCredentialsMatcher.setHashIterations(1024); userRealm.setCredentialsMatcher(hashedCredentialsMatcher); //开启缓存管理 userRealm.setCacheManager(new RedisCacheManager()); userRealm.setCachingEnabled(true);//开启全局缓存 userRealm.setAuthenticationCachingEnabled(true);//开启认证缓存 userRealm.setAuthenticationCacheName("authenticationCache"); userRealm.setAuthorizationCachingEnabled(true);//开启授权缓存 userRealm.setAuthorizationCacheName("authorizationCache"); return userRealm; } }
6.4 常见过滤器
6.5 自定义Realm
package com.chif.shiro.config; import com.chif.shiro.config.salt.MyByteSource; import com.chif.shiro.pojo.Perms; import com.chif.shiro.pojo.User; import com.chif.shiro.service.UserService; import org.apache.shiro.authc.*; 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.apache.shiro.util.ByteSource; import org.apache.shiro.util.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; //自定义的 USerRealm public class UserRealm extends AuthorizingRealm {
@Autowired UserService userService; //授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取身份信息 String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal(); System.out.println("调用授权验证"+primaryPrincipal); //根据主身份信息获取角色 和 权限信息 User user = userService.findRolesByUsername(primaryPrincipal); //授权角色信息 if (!CollectionUtils.isEmpty(user.getRoles())){
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); user.getRoles().forEach(role -> {
simpleAuthorizationInfo.addRole(role.getName()); //授予权限信息 List<Perms> perms = userService.findPermsByRoleId(role.getId()); if (!CollectionUtils.isEmpty(perms) && perms.get(0)!=null){
/ * 注意:如果你创建了一个用户,并为这个用户授予了一个角色,但这个角色并未关联任何的 授权字符串, * 那么调用数据库获得的结果是 List<Perms> perms=[null], * 此时 perms已经被初始化,里面只有一个属性null,使用判空的方法无法判别, * 此时继续遍历会报出空指针异常,此时应当添加判断条件 perms.get(0)!=null */ perms.forEach(perm -> {
simpleAuthorizationInfo.addStringPermission(perm.getName()); }); } }); return simpleAuthorizationInfo; } return null; } //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了认证"); //用户名 密码 数据库中取 //String name="root"; //String password=""; //用户token String principal= (String) token.getPrincipal(); //连接真实的数据库 User user = userService.queryUserByName(principal); System.out.println(user); if (user==null){
//没有这个人 return null;//抛出异常 未知用户名 } //参数1:返回数据库中正确的用户名 //参数2:返回数据库中正确密码 //参数3:注册时的随机盐 //参数4:提供当前realm的名字 return new SimpleAuthenticationInfo( user.getUsername(), user.getPassword(), new MyByteSource(user.getSalt()), this.getName()); } }
6.6 认证和退出的实现
Controller层实现
@RequestMapping("/login") public String login(String username,String password,String code,Model model,HttpSession session){
//比较验证码 String codes = (String) session.getAttribute("code"); try {
if (codes.equalsIgnoreCase(code)){
//获取当前的用户 Subject subject = SecurityUtils.getSubject(); //封装用户的登录数据 UsernamePasswordToken token = new UsernamePasswordToken(username,password); subject.login(token);//执行登陆方法,如果没有异常就说明OK return "index"; }else {
throw new RuntimeException("验证码错误"); } }catch (UnknownAccountException e){
//用户不存在 model.addAttribute("msg","用户名不存在"); return "login"; }catch (IncorrectCredentialsException e){
//密码错误 model.addAttribute("msg","密码错误"); return "login"; }catch (Exception e){
e.printStackTrace(); System.out.println(e.getMessage()); } return "login"; } @RequestMapping("/noauth") public String unauthorized(){
return "未经授权无法访问次页面"; } @RequestMapping("/logout") public String logout(){
Subject subject = SecurityUtils.getSubject(); subject.logout();//退出用户 return "login"; }
生成salt的工具类
package com.chif.shiro.utils; import java.util.Random; public class SaltUtils {
/ * 生成salt的静态方法 * @param n * @return */ public static String getSalt(int n){
char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0!@#$%^&*()".toCharArray(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < n; i++) {
char aChar = chars[new Random().nextInt(chars.length)]; sb.append(aChar); } return sb.toString(); } public static void main(String[] args) {
String salt=getSalt(4); System.out.println(salt); } }
6.7 连接mtbatis数据库
- 设计数据库表

- 创建数据库表
/* Navicat Premium Data Transfer Source Server : localhost_3306 Source Server Type : MySQL Source Server Version : 80015 Source Host : localhost:3306 Source Schema : db_history Target Server Type : MySQL Target Server Version : 80015 File Encoding : 65001 Date: 25/07/2021 09:17:33 */ 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) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for t_role -- ---------------------------- DROP TABLE IF EXISTS `t_role`; CREATE TABLE `t_role` ( `id` int(6) NOT NULL AUTO_INCREMENT, `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for t_role_perms -- ---------------------------- DROP TABLE IF EXISTS `t_role_perms`; CREATE TABLE `t_role_perms` ( `id` int(11) NOT NULL AUTO_INCREMENT, `roleid` int(11) NULL DEFAULT NULL, `permsid` int(11) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for t_user_role -- ---------------------------- DROP TABLE IF EXISTS `t_user_role`; CREATE TABLE `t_user_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `userid` int(11) NULL DEFAULT NULL, `roleid` int(11) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `perms` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `salt` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1; - 创建实体类
User
@Data @Accessors(chain = true) @AllArgsConstructor @NoArgsConstructor public class User implements Serializable { private String id; private String username; private String password; private String salt; //定义角色集合 private List<Role> roles; }Role
@Data @Accessors(chain = true) @AllArgsConstructor @NoArgsConstructor public class Role implements Serializable { private String id; private String name; //定义权限的集合 private List<Perms> perms; }Perms
@Data @Accessors(chain = true) @AllArgsConstructor @NoArgsConstructor public class Perms implements Serializable { private String id; private String name; private String url; } - 创建dao方法
//根据用户名查询所有角色 User findRolesByUserName(String username); //根据角色id查询权限集合 List<Perms> findPermsByRoleId(String id); - mapper实现
<resultMap id="userMap" type="User"> <id column="uid" property="id"/> <result column="username" property="username"/> <!--角色信息--> <collection property="roles" javaType="list" ofType="Role"> <id column="id" property="id"/> <result column="rname" property="name"/> </collection> </resultMap> <select id="findRolesByUserName" parameterType="String" resultMap="userMap"> SELECT u.id uid,u.username,r.id,r.NAME rname FROM t_user u LEFT JOIN t_user_role ur ON u.id=ur.userid LEFT JOIN t_role r ON ur.roleid=r.id WHERE u.username=#{username} </select> <select id="findPermsByRoleId" parameterType="String" resultType="Perms"> SELECT p.id,p.NAME,p.url,r.NAME FROM t_role r LEFT JOIN t_role_perms rp ON r.id=rp.roleid LEFT JOIN t_perms p ON rp.permsid=p.id WHERE r.id=#{id} </select>service等等…
- 数据库添加(
权限角色)信息/* Navicat Premium Data Transfer Source Server : localhost_3306 Source Server Type : MySQL Source Server Version : 80015 Source Host : localhost:3306 Source Schema : db_history Target Server Type : MySQL Target Server Version : 80015 File Encoding : 65001 Date: 25/07/2021 09:27:58 */ 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) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of t_perms -- ---------------------------- INSERT INTO `t_perms` VALUES (1, 'user:*:*', NULL); INSERT INTO `t_perms` VALUES (2, 'user:add:02', NULL); INSERT INTO `t_perms` VALUES (3, 'user:update:*', NULL); -- ---------------------------- -- Table structure for t_role -- ---------------------------- DROP TABLE IF EXISTS `t_role`; CREATE TABLE `t_role` ( `id` int(6) NOT NULL AUTO_INCREMENT, `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of t_role -- ---------------------------- INSERT INTO `t_role` VALUES (1, 'admin'); INSERT INTO `t_role` VALUES (2, 'user'); INSERT INTO `t_role` VALUES (3, 'product'); -- ---------------------------- -- Table structure for t_role_perms -- ---------------------------- DROP TABLE IF EXISTS `t_role_perms`; CREATE TABLE `t_role_perms` ( `id` int(11) NOT NULL AUTO_INCREMENT, `roleid` int(11) NULL DEFAULT NULL, `permsid` int(11) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of t_role_perms -- ---------------------------- 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, 3); -- ---------------------------- -- Table structure for t_user_role -- ---------------------------- DROP TABLE IF EXISTS `t_user_role`; CREATE TABLE `t_user_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `userid` int(11) NULL DEFAULT NULL, `roleid` int(11) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of t_user_role -- ---------------------------- 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, 3, 3); -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `perms` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `salt` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES (1, 'admin', '18010d23f6bd4d702e35c849a6790af9', 'user:*:01', 'b%pLB!*q'); INSERT INTO `user` VALUES (2, 'chif', 'd4feed7e70ce0269f5d85135a34f0d6d', 'user:*:02', 'HpR*B(pk'); INSERT INTO `user` VALUES (5, 'liu', 'd4feed7e70ce0269f5d85135a34f0d6d', 'user:*:05', 'HpR*B(pk'); INSERT INTO `user` VALUES (16, '', '18010d23f6bd4d702e35c849a6790af9', NULL, 'b%pLB!*q'); INSERT INTO `user` VALUES (17, 'ww', 'd4feed7e70ce0269f5d85135a34f0d6d', NULL, 'HpR*B(pk'); SET FOREIGN_KEY_CHECKS = 1;
6.8 使用缓存Cachemanager
6.8.1 Cache 作用
- Cache 缓存: 计算机内存中一段数据
- 作用: 用来减轻DB的访问压力,从而提高系统的查询效率
- 流程:

6.8.2 使用shiro中默认EhCache实现缓存
1.引入依赖
<!--引入shiro和ehcache--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.5.3</version> </dependency>
2.开启缓存
//3.创建自定义realm @Bean public Realm getRealm(){
CustomerRealm customerRealm = new CustomerRealm(); //修改凭证校验匹配器 HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); //设置加密算法为md5 credentialsMatcher.setHashAlgorithmName("MD5"); //设置散列次数 credentialsMatcher.setHashIterations(1024); customerRealm.setCredentialsMatcher(credentialsMatcher); //开启缓存管理器 customerRealm.setCachingEnabled(true); customerRealm.setAuthorizationCachingEnabled(true); customerRealm.setAuthorizationCachingEnabled(true); customerRealm.setCacheManager(new EhCacheManager()); return customerRealm; }
3.启动刷新页面进行测试
- 注意:如果控制台没有任何sql展示说明缓存已经开启
# 开启控制台SQL日志注解 logging.level.com.chif.shiro.mapper=debug
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/231226.html原文链接:https://javaforall.net
