最全Shiro教程,一篇学会Shiro权限管理

您所在的位置:网站首页 shiro缓存管理 最全Shiro教程,一篇学会Shiro权限管理

最全Shiro教程,一篇学会Shiro权限管理

2024-07-13 08:00| 来源: 网络整理| 查看: 265

声明:本文是博主观看bilibili上Java涛哥视频学习的Shiro框架所整理笔记,学完思路清晰,原文代码大致相同,原视频链接附上,方便以后学习查看。 本文项目源码加数据库

https://download.csdn.net/download/qq_45299673/69324339

Shiro 一、权限管理1.1 基于主页的权限管理1.2 基于用户和权限的权限管理1.3 基于角色的访问控制(RBAC) 二、Shiro2.1 认证和授权2.2 常见的安全框架2.3 shrio核心功能2.4 Shiro核心组件2.5 shiro的使用2.6 shrio认证流程 三、SpringBoot整合Shiro3.1 导入依赖application.yml配置 3.2 Shiro配置3.3 测试3.4 内置JDBCRealm作为数据源JdbcRealm规定的表结构 3.5 shiro的标签的使用常用标签 四、自定义Realm实现权限管理4.1 数据库设计4.2 创建DAO层4.3 application.yml4.4 pom.xml4.5 自定义Realm配置类4.6 shiro配置4.7 shiro业务层4.8 Controller层4.9 整合layUI 五、加密5.1 Shiro加密5.2 密码认证 六、Shiro的退出登录七、授权7.1 HTML授权7.2 过滤器授权7.3 注解授权7.4 手动授权 ​ Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境。

一、权限管理

不同身份的人进入系统所完成的操作不同,如下图,当一个系统包含左侧所有菜单功能时,要求不同人员登录展示不同权限下的菜单,这时候就需要学习权限管理,看完本文就可轻松掌握。 请添加图片描述

1.1 基于主页的权限管理

设计多种页面,当不同权限的用户访问时,跳转不同的用户,如下图,用户1登录跳转到index1.html,用户2登录跳转到index2.html,缺陷比较大且繁琐,不建议使用。 请添加图片描述

缺点:适用于用户级别较少的,不能动态分配权限

1.2 基于用户和权限的权限管理

利用用户表、用户权限表、权限表三张表,每个用户在中间表分配权限 请添加图片描述 实现权限的动态分配,但是每个用户对应一个用户权限,10个人就得10个,数据比较冗余,这样就衍生了下面的五张表

1.3 基于角色的访问控制(RBAC)

创建用户表、角色表、权限表和两张中间表用户角色表、角色权限表五张表,每次新加用户时只需要授予角色就可获得相对的权限。 请添加图片描述 给同类人员的其中一个人授予权限可以再加一张用户权限表,直接授予权限。 在这里插入图片描述

二、Shiro 2.1 认证和授权 认证:对用户的身份进行检查(登录验证) 授权:对用户的权限进行检查(是否有对应的操作权限)

在这里插入图片描述

2.2 常见的安全框架 shiro:Apache Shrio是功能强大并且易用的Java安全框架 Spring Security:基于Spring的安全框架,依赖Spring OAuth2:第三方授权框架(QQ、微信) 自定义安全认证中心 2.3 shrio核心功能

在这里插入图片描述

Anthentication 认证,验证用户是否有相应的身份 登录认证 Authorization 授权,权限验证,通过认证的用户检查是否有权限或者角色 Session Management 会话管理,用户在认证成功后创建会话,在没有退出之前,当前用户的所有信息都会保存在这个会话中 Cryptograsphy 加密,对敏感信息加密

支持的特性: 1.Web Support Shrio提供了过滤器,可以通过过滤器拦截web请求来处理web应用的访问控制 2.Caching 缓存支持,shiro可以缓存用户信息以及用户的角色权限信息,可以提高执行效率 3.concurrency shiro支持多线程应用 4.Run As 允许一个用户以另一种身份去访问 5.Remeber Me 记住密码 6.Testing 提供测试支持 Shiro是一个安全框架,不提供用户、权限的维护,用户的权限管理需要我们去设计

2.4 Shiro核心组件

在这里插入图片描述 Subject、Security Manager、Realms

Subject:表示待认证和授权的用户Security Manager:Shiro框架的核心,Shiro就是通过Security Manager来进行内部实例的管理,并通过它来提供安全管理的各种服务Realm:相当于shiro进行认证和授权的数据源 在这里插入图片描述 2.5 shiro的使用

1.添加maven依赖

org.apache.shiro shiro-core 1.4.1

2.创建shiro的配置文件

在resource下创建ini后缀文件

[users] zhangsan=123456,seller lisi=123123,ckmgr admin=admin,admin [roles] admin=* seller=order-add,order-del,order-list ckmgr=ck-add,ck-del,ck-list

3.使用测试

public class ShiroTest { public static void main(String[] args) { Scanner sc=new Scanner(System.in); System.out.println("请输入账号:"); String username = sc.next(); System.out.println("请输入密码:"); String password = sc.next(); //1.创建安全管理器 DefaultSecurityManager securityManager=new DefaultSecurityManager(); //2.创建realm IniRealm iniRealm=new IniRealm("classpath:shiro.ini"); //3.将realm设置给安全管理器 securityManager.setRealm(iniRealm); //4.将Realm设置给SecurityUtil工具 SecurityUtils.setSecurityManager(securityManager); //5.通过SecurityUtil工具类获取subject对象 Subject subject=SecurityUtils.getSubject(); //认证流程 //将认证账号和密码封装到token中 UsernamePasswordToken token=new UsernamePasswordToken(username,password); //通过subject对象调用login方法进行认证 boolean flag=false; try{ subject.login(token); flag=true; }catch (IncorrectCredentialsException e){ flag=false; } System.out.println(flag?"登录成功":"登录失败"); //授权 //判断是否有某个角色 System.out.println(subject.hasRole("seller")); //判断是否有某个权限 System.out.println(subject.isPermitted("order-del")); } } 2.6 shrio认证流程

在这里插入图片描述

三、SpringBoot整合Shiro 3.1 导入依赖 org.springframework.boot spring-boot-starter-parent 2.0.1.RELEASE com.alibaba druid-spring-boot-starter 1.1.10 org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 1.1.1 mysql mysql-connector-java org.apache.shiro shiro-spring 1.4.1 application.yml配置 spring: datasource: druid: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8 username: root password: 123456 initial-size: 1 min-idle: 1 max-active: 20 mybatis: type-aliases-package: com.zx.entity mapper-locations: classpath:com/zx/dao/*Mapper.xml 3.2 Shiro配置

SpringBoot没有提供对Shiro的自动配置,因为Spring家族有自己的安全框架

config/shiroConfig.java import org.apache.shiro.realm.text.IniRealm; 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 { @Bean public IniRealm getIniRealm(){ IniRealm iniRealm=new IniRealm("classpath:shiro.ini"); return iniRealm; } @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(IniRealm iniRealm){ DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(); //securityManager要完成校验,需要realm securityManager.setRealm(iniRealm); return securityManager; } @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean filter=new ShiroFilterFactoryBean(); filter.setSecurityManager(defaultWebSecurityManager); //设置shiro的拦截规则 //anon 匿名用户可访问 authc 认证用户可访问 //user 使用RemeberMe的用户可访问 perms 对应权限可访问 //role 对应的角色可访问 Map filterMap=new HashMap(); filterMap.put("/","anon"); filterMap.put("/login.html","anon"); filterMap.put("/register.html","anon"); filterMap.put("/user/login","anon"); filterMap.put("/user/register","anon"); filterMap.put("/static/**","anon"); filterMap.put("/**","authc"); filter.setFilterChainDefinitionMap(filterMap); filter.setLoginUrl("/login.html"); //设置未授权页面跳转到登录页面 filter.setUnauthorizedUrl("/login.html"); return filter; } } 3.3 测试 UserServiceImpl.java@Service public class UserServiceImpl { public void checkLogin(String username,String Password) throws Exception{ Subject subject= SecurityUtils.getSubject(); UsernamePasswordToken token=new UsernamePasswordToken(username,Password); subject.login(token); } } UserController.java@Controller @RequestMapping("/user") public class UserController { @Autowired UserServiceImpl userService; @RequestMapping("/login") public String login(String username,String password){ try { userService.checkLogin(username,password); return "index"; } catch (Exception e) { System.out.println("密码错误"); return "login"; } } } login.html DOCTYPE html> Title login页面 账号: 密码:

通过shiro.ini定义正确的登录密码

[user] admin=admin

在这里插入图片描述 密码正确跳转到index.html 密码错误跳转到login.html

3.4 内置JDBCRealm作为数据源

在这里插入图片描述 如果使用JdbcRealm,则必须提供JdbcRealm所需要的表结构(权限设计)

JdbcRealm规定的表结构

在这里插入图片描述 表中的字段必须保持一致,可以加字段

用户信息表:users

create table users( id int primary key auto_increment, username varchar(60) not null unique, password varchar(20) not null, password_salt varchar(20) );

角色信息表: user_roles

create table user_roles( id int primary key auto_increment, username varchar(60) not null, role_name varchar(100) not null );

权限信息表:roles_permissions

create table roles_permissions( id int primary key auto_increment, role_name varchar(100) not null, permission varchar(100) not null );

在这里插入图片描述 从图中可以看出用户所对应的权限

步骤

创建SpringBoot整合Mybatis 添加shiro依赖

配置Shiro

@Configuration public class ShiroConfig { @Bean public JdbcRealm getJDBCRealm(DataSource dataSource){ JdbcRealm jdbcRealm=new JdbcRealm(); //JdbcRealm会自行从数据库查询用户及权限数据(数据库表结构必须符合JdbcRealm规范) jdbcRealm.setDataSource(dataSource); //JdbcRealm默认开启认证功能,需要手动开启授权功能 jdbcRealm.setPermissionsLookupEnabled(true); return jdbcRealm; } @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(JdbcRealm jdbcRealm){ DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(); //securityManager要完成校验,需要realm securityManager.setRealm(jdbcRealm); return securityManager; } @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean filter=new ShiroFilterFactoryBean(); filter.setSecurityManager(defaultWebSecurityManager); //设置shiro的拦截规则 //anon 匿名用户可访问 authc 认证用户可访问 //user 使用RemeberMe的用户可访问 perms 对应权限可访问 //role 对应的角色可访问 Map filterMap=new HashMap(); filterMap.put("/","anon"); filterMap.put("/login.html","anon"); filterMap.put("/register.html","anon"); filterMap.put("/user/login","anon"); filterMap.put("/user/register","anon"); filterMap.put("/static/**","anon"); filterMap.put("/**","authc"); filter.setFilterChainDefinitionMap(filterMap); filter.setLoginUrl("/login.html"); //设置未授权页面跳转到登录页面 filter.setUnauthorizedUrl("/login.html"); return filter; } }

测试结果同上 在这里插入图片描述

3.5 shiro的标签的使用

​ 当用户认证进入到主页之后,需要显示用户信息及当前用户的权限信息,shiro提供了一套标签用于在页面来进行权限数据的呈现

Shiro提供了可供JSP使用的标签以及Thymeleaf标签

JSP页面中引用

Thymeleaf模板中引用

在pom.xml中导入thymeleaf模板对shiro标签的支持依赖 com.github.theborakompanioni thymeleaf-extras-shiro 2.0.0 在ShiroConfig中配置Shiro的方言支持 @Configuration public class ShiroConfig { @Bean public ShiroDialect getShiroDialect(){ return new ShiroDialect(); } } Thymeleaf模板中引入shiro的命名空间 常用标签 标签,登录后不显示,游客状态下显示 标签 ,登录后显示 显示登录用户的用户名 ## 显示用户角色 ## 显示用户权限

具体用法如下: 数据库添加如下信息 在这里插入图片描述

“zhangsan”是管理员admin角色,拥有所有*权限 “lisi”是仓库管理员cmanager角色,拥有sys:c:*权限 “wangwu”是行政人员xmanager角色,拥有sys:X:*权限 实现当不同用户登录后显示不同的权限菜单 DOCTYPE html> Title index页面 欢迎游客访问,去登录 已登录用户访问 用户:欢迎你! 当前用户为超级管理员 行政人员 仓管人员 仓库管理 入库 出库 修改 查询 订单管理 添加订单 删除订单 修改订单 查询查询

当游客身份登录 请添加图片描述 当admin管理员登录 在这里插入图片描述 当仓管人员登录 在这里插入图片描述 当行政人员登录 在这里插入图片描述

四、自定义Realm实现权限管理

当要使用自己定义的数据结构表,就需要告诉Realm,更改为自己设计的数据源

4.1 数据库设计

在这里插入图片描述

SQL语句

SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for `tb_permissions` -- ---------------------------- DROP TABLE IF EXISTS `tb_permissions`; CREATE TABLE `tb_permissions` ( `permission_id` int NOT NULL AUTO_INCREMENT, `permission_code` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `permission_name` varchar(60) DEFAULT NULL, PRIMARY KEY (`permission_id`) ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; -- ---------------------------- -- Records of tb_permissions -- ---------------------------- INSERT INTO `tb_permissions` VALUES ('1', 'sys:c:save', '入库'); INSERT INTO `tb_permissions` VALUES ('2', 'sys:c:delete', '出库'); INSERT INTO `tb_permissions` VALUES ('3', 'sys:c:update', '修改'); INSERT INTO `tb_permissions` VALUES ('4', 'sys:c:find', '查询'); INSERT INTO `tb_permissions` VALUES ('5', 'sys:x:save', '新增订单'); INSERT INTO `tb_permissions` VALUES ('6', 'sys:x:delete', '删除订单'); INSERT INTO `tb_permissions` VALUES ('7', 'sys:x:update', '修改订单'); INSERT INTO `tb_permissions` VALUES ('8', 'sys:x:find', '查询订单'); INSERT INTO `tb_permissions` VALUES ('9', 'sys:k:save', '新增客户'); INSERT INTO `tb_permissions` VALUES ('10', 'sys:k:delete', '删除客户'); INSERT INTO `tb_permissions` VALUES ('11', 'sys:k:update', '修改客户'); INSERT INTO `tb_permissions` VALUES ('12', 'sys:k:find', '查询客户'); -- ---------------------------- -- Table structure for `tb_roles` -- ---------------------------- DROP TABLE IF EXISTS `tb_roles`; CREATE TABLE `tb_roles` ( `role_id` int NOT NULL AUTO_INCREMENT, `role_name` varchar(60) NOT NULL, PRIMARY KEY (`role_id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; -- ---------------------------- -- Records of tb_roles -- ---------------------------- INSERT INTO `tb_roles` VALUES ('1', 'admin'); INSERT INTO `tb_roles` VALUES ('2', 'cmanager'); INSERT INTO `tb_roles` VALUES ('3', 'xmanager'); INSERT INTO `tb_roles` VALUES ('4', 'kmanager'); INSERT INTO `tb_roles` VALUES ('5', 'zmanager'); -- ---------------------------- -- Table structure for `tb_roles_permission` -- ---------------------------- DROP TABLE IF EXISTS `tb_roles_permission`; CREATE TABLE `tb_roles_permission` ( `rid` int NOT NULL, `pid` int NOT NULL, KEY `FK_pid` (`pid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; -- ---------------------------- -- Records of tb_roles_permission -- ---------------------------- INSERT INTO `tb_roles_permission` VALUES ('2', '1'); INSERT INTO `tb_roles_permission` VALUES ('2', '2'); INSERT INTO `tb_roles_permission` VALUES ('2', '3'); INSERT INTO `tb_roles_permission` VALUES ('2', '4'); INSERT INTO `tb_roles_permission` VALUES ('3', '5'); INSERT INTO `tb_roles_permission` VALUES ('3', '6'); INSERT INTO `tb_roles_permission` VALUES ('3', '7'); INSERT INTO `tb_roles_permission` VALUES ('3', '8'); INSERT INTO `tb_roles_permission` VALUES ('3', '9'); INSERT INTO `tb_roles_permission` VALUES ('3', '10'); INSERT INTO `tb_roles_permission` VALUES ('3', '11'); INSERT INTO `tb_roles_permission` VALUES ('3', '12'); INSERT INTO `tb_roles_permission` VALUES ('3', '4'); INSERT INTO `tb_roles_permission` VALUES ('4', '11'); INSERT INTO `tb_roles_permission` VALUES ('4', '12'); INSERT INTO `tb_roles_permission` VALUES ('5', '4'); INSERT INTO `tb_roles_permission` VALUES ('5', '8'); INSERT INTO `tb_roles_permission` VALUES ('5', '12'); -- ---------------------------- -- Table structure for `tb_users` -- ---------------------------- DROP TABLE IF EXISTS `tb_users`; CREATE TABLE `tb_users` ( `user_id` int NOT NULL AUTO_INCREMENT, `username` varchar(20) NOT NULL, `password` varchar(20) NOT NULL, `password_salt` varchar(60) DEFAULT NULL, PRIMARY KEY (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; -- ---------------------------- -- Records of tb_users -- ---------------------------- INSERT INTO `tb_users` VALUES ('1', 'zhangsan', '123456', null); INSERT INTO `tb_users` VALUES ('2', 'lisi', '123456', null); INSERT INTO `tb_users` VALUES ('3', 'wangwu', '123456', null); INSERT INTO `tb_users` VALUES ('4', 'zhaoliu', '123456', null); INSERT INTO `tb_users` VALUES ('5', 'chenqi', '123456', null); -- ---------------------------- -- Table structure for `tb_users_roles` -- ---------------------------- DROP TABLE IF EXISTS `tb_users_roles`; CREATE TABLE `tb_users_roles` ( `uid` int NOT NULL, `rid` int NOT NULL, KEY `FK_role` (`rid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; -- ---------------------------- -- Records of tb_users_roles -- ---------------------------- INSERT INTO `tb_users_roles` VALUES ('1', '1'); INSERT INTO `tb_users_roles` VALUES ('2', '2'); INSERT INTO `tb_users_roles` VALUES ('3', '3'); INSERT INTO `tb_users_roles` VALUES ('4', '4'); INSERT INTO `tb_users_roles` VALUES ('5', '5'); INSERT INTO `tb_users_roles` VALUES ('1', '2'); INSERT INTO `tb_users_roles` VALUES ('1', '3'); INSERT INTO `tb_users_roles` VALUES ('1', '4'); INSERT INTO `tb_users_roles` VALUES ('1', '5');

在这里插入图片描述 从表中就可以查询出lisi的角色为cmanager,权限有[入库,出库,修改,查询]

一个人可以关联多个角色,权限取多个角色的并集

4.2 创建DAO层 //UserDao.java //根据用户名查询用户信息 @Mapper public interface UserDao { User getUserByUsername(String username); } //RoleDao.java //根据用户名查询角色 @Mapper public interface RoleDao { Set getRoleNamesByUsername(String username); } //PermissionDao.java //根据用户明查询权限 @Mapper public interface PermissionDao { Set getPermissionByUsername(String username); }

编写Mapper映射

UserMapper.xml

select * from tb_users where username=#{username}

RoleMapper.xml

select role_name from tb_users inner join tb_users_roles on user_id=uid inner join tb_roles on rid=role_id where username=#{username}

PermissionMapper.xml

select permission_code from tb_users inner join tb_users_roles on user_id=uid inner join tb_roles on tb_users_roles.rid=role_id inner join tb_roles_permission on role_id=tb_roles_permission.rid inner join tb_permissions on pid=permission_id where username=#{username} 4.3 application.yml spring: datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/shiro?useUnicode=true&characterEncoding=utf8 username: root password: 123456 initial-size: 1 min-idle: 1 max-active: 20 mybatis: type-aliases-package: com/zx/shiro2/beans mapper-locations: classpath:mappers/*.xml 4.4 pom.xml 4.0.0 org.springframework.boot spring-boot-starter-parent 2.6.1 com.zx shiro2 0.0.1-SNAPSHOT shiro2 Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-web org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test com.alibaba druid-spring-boot-starter 1.1.10 org.mybatis.spring.boot mybatis-spring-boot-starter 1.1.1 mysql mysql-connector-java org.apache.shiro shiro-spring 1.4.1 com.github.theborakompanioni thymeleaf-extras-shiro 2.0.0 junit junit test 4.5 自定义Realm配置类

要使用自己设计的权限数据库,这个时候的Realm就要继承AuthorizingRealm类使它成为一个Realm类。

在config配置包里创建MyRealm.java

/** * 1.创建一个类继承AuthorizingRealm类(实现了Realm接口类) * 2.重写doGetAuthorizationInfo和doGetAuthenticationInfo方法 * 3.重写getName方法返回当前realm的自定义名称 */ public class MyRealm extends AuthorizingRealm { @Resource private UserDao userDao; @Resource private RoleDao roleDao; @Resource private PermissionDao permissionDao; @Override public String getName() { return "myRealm"; } /** * 获取授权数据(角色权限信息) * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //获取用户的用户名 String username = (String) principalCollection.iterator().next(); //根据用户名查询用户角色 Set roles = roleDao.getRoleNamesByUsername(username); //根据用户名查询用户权限 Set permissions = permissionDao.getPermissionByUsername(username); SimpleAuthorizationInfo info=new SimpleAuthorizationInfo(); info.setRoles(roles); info.setStringPermissions(permissions); return info; } /** * 获取认证的安全数据(从数据库查询到的用户正确数据) * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //参数authenticationToken就是传递的 subject.login(token) UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken; //从token中获取用户名 String username = token.getUsername(); //根据用户名从数据库查询用户安全数据 User user = userDao.getUserByUsername(username); AuthenticationInfo info=new SimpleAuthenticationInfo(username,user.getPassword(),getName()); return info; } } 4.6 shiro配置

ShiroConfig.java

@Configuration public class ShiroConfig { //Shiro的方言 @Bean public ShiroDialect getShiroDialect(){ return new ShiroDialect(); } //自定义Realm @Bean public MyRealm getMyRealm(){ MyRealm myRealm=new MyRealm(); return myRealm; } //SecurityManager安全管理器 @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){ DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(); //securityManager要完成校验,需要realm securityManager.setRealm(myRealm); return securityManager; } //过滤器 @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean filter=new ShiroFilterFactoryBean(); filter.setSecurityManager(defaultWebSecurityManager); //设置shiro的拦截规则 //anon 匿名用户可访问 authc 认证用户可访问 //user 使用RemeberMe的用户可访问 perms 对应权限可访问 //role 对应的角色可访问 Map filterMap=new HashMap(); filterMap.put("/","anon"); filterMap.put("/login.html","anon"); filterMap.put("/register.html","anon"); filterMap.put("/user/login","anon"); filterMap.put("/user/register","anon"); filterMap.put("/static/**","anon"); filterMap.put("/**","authc"); filter.setFilterChainDefinitionMap(filterMap); filter.setLoginUrl("/login.html"); //设置未授权页面跳转到登录页面 filter.setUnauthorizedUrl("/login.html"); return filter; } } 4.7 shiro业务层 @Service public class UserServiceImpl { public void checkLogin(String username,String Password){ Subject subject= SecurityUtils.getSubject(); UsernamePasswordToken token=new UsernamePasswordToken(username,Password); subject.login(token); } } 4.8 Controller层 @Controller @RequestMapping("/user") public class UserController { @Autowired UserServiceImpl userService; @RequestMapping("/login") public String login(String username,String password){ try { userService.checkLogin(username,password); return "index"; } catch (Exception e) { System.out.println("密码错误"); return "login"; } } } 4.9 整合layUI

导入layui包,官网复制后台框架代码

DOCTYPE html> Shiro管理系统 菜单显示 nav 1 nav 2 nav 3 nav groups menu 11 menu 22 menu 33 Your Profile Settings Sign out 仓库管理 入库 出库 修改 查询 订单管理 新增订单 删除订单 修改订单 查询订单 客户管理 新增客户 删除客户 修改客户 查询客户 内容主体区域。记得修改 layui.css 和 js 的路径 底部固定区域 //JS layui.use(['element', 'layer', 'util'], function(){ var element = layui.element ,layer = layui.layer ,util = layui.util ,$ = layui.$; //头部事件 util.event('lay-header-event', { //左侧菜单事件 menuLeft: function(othis){ layer.msg('展开左侧菜单的操作', {icon: 0}); } ,menuRight: function(){ layer.open({ type: 1 ,content: '处理右侧面板的操作' ,area: ['260px', '100%'] ,offset: 'rt' //右上角 ,anim: 5 ,shadeClose: true }); } }); });

实现不同权限的管理员登录,展示的菜单不同

zhangsan 超级管理员 显示全部菜单 在这里插入图片描述 wangwu xmanager管理员,对仓库管理只有查看的权限 在这里插入图片描述

layui实现点击左边菜单,内容右边显示 在这里插入图片描述 在这里插入图片描述

五、加密

用户密码在存储到数据库之前根据一定的加密规则加密为密文。加密规则可以自定义,在项目开发中通常使用BASE64和MD5编码方式进行加密

​ BASE64:可以反编码的编码方式。

​ MD5:不可逆的编码方式(网站上常见的MD5解密,只不过是列出常见密码的密文进行查询,密码一旦复杂就解密不出来了,为了防止暴力穷举破解,可以加盐加密)

在这里插入图片描述

Shiro提供了加密功能,对输入的密码进行加密后再认证 5.1 Shiro加密 ```java @RequestMapping("/register") public String register(String username,String password){ //注册时对密码进行加密 Md5Hash md5Hash=new Md5Hash(password); //加盐加密 int salt=new Random().nextInt(90000)+10000; //10000-99999 Md5Hash md5Hash1=new Md5Hash(password,salt+""); //加盐加密+Hash次数 Md5Hash md5Hash2=new Md5Hash(password,salt+"",1); //TODO 此处省略存储到数据库代码 return "login"; } ``` 5.2 密码认证

在ShiroConfig中配置加密规则

修改上文的ShiroConfig.java,设置加密规则认证时就生效,没有设置加密规则,默认明文校验

. . . @Bean public HashedCredentialsMatcher getHashedCredentialsMatcher(){ HashedCredentialsMatcher matcher=new HashedCredentialsMatcher(); //matcher就是用来指定加密规则 //加密方式 matcher.setHashAlgorithmName("md5"); //hash次数,这里的hash次数要与存储时加密的hash次数保持一致 matcher.setHashIterations(1); return matcher; } //自定义Realm @Bean public MyRealm getMyRealm(HashedCredentialsMatcher matcher){ MyRealm myRealm=new MyRealm(); //设置加密规则 myRealm.setCredentialsMatcher(matcher); return myRealm; } . . .

在这里插入图片描述

可以正常登录,如果密码加盐了,Realm在返回认证信息时需要返回盐数据,在自定义Realm中修改

ByteSource.Util.bytes(user.getPasswordSalt()),

在这里插入图片描述

六、Shiro的退出登录 在Shiro过滤器中进行配置,配置logout对应的路径 在这里插入图片描述在页面的退出按钮上添加路径/logout 在这里插入图片描述 当点击退出登录按钮时,shiro会拦截logout的路径调用subject.logout()登出。 七、授权

​ 一般的授权方式有两种:一、HTML授权,即用户登录只显示自己权限的菜单,没有权限的菜单不显示。二、过滤器授权,对所有用户显示所有菜单功能,当用户点击菜单后再验证是否有此权限,无权限提示权限不足。

7.1 HTML授权 shiro标签 入库 7.2 过滤器授权

在这里插入图片描述

7.3 注解授权 配置Spring对Shiro的注解支持 //使Shiro的注解可以加载执行 @Bean public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){ DefaultAdvisorAutoProxyCreator autoProxyCreator=new DefaultAdvisorAutoProxyCreator(); autoProxyCreator.setProxyTargetClass(true); return autoProxyCreator; } //权限注解加载 @Bean public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager){ AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(defaultWebSecurityManager); return advisor; } 在请求的控制器添加权限注解 //没有sys:k:find权限不允许访问 @RequiresPermissions("sys:k:find") @RequestMapping("/list") public String list(){ return "list"; }

当无权人员访问时会抛出AuthorizationException异常,可以配置全局异常类。

@ControllerAdvice public class GlobalException { @ExceptionHandler public String doException(Exception e){ if(e instanceof AuthorizationException){ return "error"; } return null; } } 7.4 手动授权

在代码中进行权限校验,一般写在业务层

Subject subject=SecurityUtils.getSubject(); if(subject.isPermitted("sys:k:find")){ //业务逻辑 }else{ //无权限处理 }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3