SpringBoot 整合 Shiro

  • 一、Shiro 的简介
  • 二、Shiro 的实现。
    • 独立应用程序
    • 2.1、SSM 框架配置文件的方式 集成 Apache Shiro 。
    • 2.2、Spring Boot 集成 Apache Shiro 。
  • 三、Shiro 的方法总结。
    • 3.1、Shiro 支持三种方式的授权。
    • 3.2、@RequiresRoles 和 @RequiresPermissions 注解不生效。
    • 3.3、Shiro 的注解。
    • 3.4、unauthorizedUrl 无效。
    • 3.5、AJAX 请求,提示无角色无权限。

2019-04-30, 明天是五一劳动节,准备在4月结束前把 Token 令牌登录(SpringBoot 整合 JWT )的项目接口与将文件管理系统的接口对接,发现学长给的这个用户认证登录的接口有些问题(后续再说),没能顺利的进行。

  1. 在学习 SSM 框架的时候,有接触到 Shiro ,其中的登录是通过 Token 完成的。这样我便开始 SpringBoot 整合 Shiro。

一、Shiro 的简介

  1. Shiro 的官网 :http://shiro.apache.org/
  2. 将Apache Shiro集成到基于Spring的应用程序中

  Shiro 完整架构图

   Shiro 是 Apache 下的一个开源项目(Apache Shiro),是一个易用与 Java 项目的安全框架,提供了 认证、授权、加密、会话管理,与 Spring Security 一样都是做了一个权限的安全框架。
  Shiro 核心的三大组件

  Shiro 的三大核心组件:
    1、Subject 当前用户。
    2、SecurityManage 管理所有的 Subject 。
    3、Reamls 权限信息的验证 。
   除了三大组件,还要认识的内容:
    * authenticator:认证器,主体进行认证最终通过authenticator进行的。
    * authorizer:授权器,主体进行授权最终通过authorizer进行的。
    * sessionManager:web应用中一般是用web容器对session进行管理,shiro也提供一套 - session管理的方式。
    * SessionDao: 通过SessionDao管理session数据,针对个性化的session数据存储需要使用sessionDao。
    * cache Manager:缓存管理器,主要对session和授权数据进行缓存,比如将授权数据通过cacheManager进行缓存管理,和ehcache整合对缓存数据进行管理。
    * realm:域,领域,相当于数据源,通过realm存取认证、授权相关数据。
    * cryptography:密码管理,提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。比如 md5散列算法。
  Shiro 的实现要点:
    1、实现 Reamls 的 Authentication(验证用户的身份) 与 Authorization(用户授权访问控制)。
    2、Shiro 是通过 Filter(过滤器)来实现的,就好比 SpringMVC 使用 DispatchServlet 来做控制,就是多个过滤器按照顺序执行。Shiro 是通过 URL 匹配规则来进行过滤和权限校验的,所以我们需要定义一系列的 URL 规则和访问权限。

Shiro 默认的拦截器 拦截器描述 用例 过滤器的类 org.apache.shiro.web.filter
anon 可匿名访问 注册等可以匿名访问。/admin/register/**=anon .authc.AnonymousFilter
authc 认证成功后才能使用(Authorization 执行成功) 设置需要认证权限的界面。/user/**=authc .authc.FormAuthenticationFilter
logout 注销登录的时候,任何 Session 都失效,任何身份都将失效 用户退出。/logout=logout .authc.LogoutFilter
authcBasic 表示需通过 HttpBasic验证 /user/**=authBasic .authc.BasicHttpAuthenticationFilter
perms 权限过滤器 /admins/**=perms[user:add:*];/admins/user/**=perms[“user:add:*,user:modify:*”] .authz.PermissionsAuthorizationFilter
port 端口过滤器,可以设置是否是指定端口如果不是跳转到登录页面 /admins/**=port[8081] .authz.PortFilter
rest http方法过滤器 可以指定如post不能进行访问等,/admins/user/**=rest[user:method],其中method 为 post、get等 .authz.HttpMethodPermissionFilter
roles 角色过滤器,判断当前用户是否指定角色。当有多个参数时,每个参数通过才算通过,相当于 hasAllRoles() 方法 /admins/**=roles[“admin,guest”] .authz.RolesAuthorizationFilter
ssl 请求需要通过ssl,如果不是跳转登录页 暂无 .authz.SslFilter
user 如果访问一个已知用户,比如记住我功能,走这个过滤器 暂无 .authc.UserFilter
noSessionCreation 阻止在请求期间创建新的会话。以保证无状态的体验 暂无 .session.NoSessionCreationFilter

    3、Shiro 通过提供的会话管理可以获取 Session 中的信息,同样可以使用 CacheManage 来管理。
    4、Shiro 的认证流程:
     (1)、在登录页面输入账号密码,传递给 Controller,在 Controller 中通过 Security.getSubject() 获取当前的 Subject 。
     (2)、通过 Subject 的 isAuthenticated() ,验证当前用户是否已经被认证。
     (3)、如果没有被认证,则开始认证。
     (4)、将从前台传来的账号密码封装到一个 UsernamePasswordToken 对象中。
     (5)、调用当前 Subject 的 login() 方法。这会把 token 作为参数传递到自定义的 Realm 的 doGetAuthenticationInfo()方法中。
     (6)、在 doGetAuthenticationInfo() 方法中,首先将 AuthenticationToken 转换为 UsernamePasswordToken 对象,然后调用 Service 层,根据 UsernamePasswordToken 中的用户名到数据库中去查询密码。
     (7)、由 Shiro 完成密码的比对,密码的比对是通过 AuthenticatingRealm 的 credentialsMatcher 属性来进行比对的。
    5、Shiro 的授权流程。
     (1)、构造 SecurityManager 环境后,对 subject 进行授权,调用方法 isPermitted(”permission串”)
     (2)、SecurityManager 执行授权,通过 ModularRealmAuthorizer 执行授权
     (3)、ModularRealmAuthorizer 执行 realm(自定义的CustomRealm)从数据库查询权限数据
调用realm的授权方法:doGetAuthorizationInfo()
     (4)、realm 从数据库查询权限数据,返回ModularRealmAuthorizer
     (5)、ModularRealmAuthorizer 调用 PermissionResolver 进行权限串比对
     (6)、如果比对后,isPermitted 中”permission串”在 realm 查询到权限数据中,说明用户访问 permission 串有权限,否则没有权限,抛出异常。

二、Shiro 的实现。

将Apache Shiro集成到基于Spring的应用程序中(SSM 实现)

独立应用程序

我是直接开发的 Web ,这里是官网标出来,我大概理解了一下。如有什么不对的地方,请见谅。

  • 自定义的 Realm 必须继承 AuthorizingRealm,并实现两个 Abstract 方法 doGetAuthorizationInfo 和 doGetAuthenticationInfo。

  • 页面的登录表单(Login Form)按照官方文档的写法,表单元素的名字都和文档一样(即:username、password 、rememberMe),表单登录(Login Action)只需要完成验证失败的跳转。验证成功变跳转至 successUrl。

默认的 FormAuthenticationFilter 会找这三个requestparameters:username、password 、rememberMe。设置FormAuthenticationFilter的这几个参数。authc.loginUrl = /login.html authc.usernameParam = adminNameauthc.passwordParam = adminPassauthc.rememberMeParam = addCookie

2.1、SSM 框架配置文件的方式 集成 Apache Shiro 。

SSM 框架 Shiro 的实现,请参考:https://blog.csdn.net/Roobert_Chao/article/details/89971383

2.2、Spring Boot 集成 Apache Shiro 。

Spring Boot 集成 Apache Shiro,请参考: https://blog.csdn.net/Roobert_Chao/article/details/89971828
Spring Boot 集成 Apache Shiro 并添加 Cache ,请参考:https://blog.csdn.net/Roobert_Chao/article/details/90046565

三、Shiro 的方法总结。

3.1、Shiro 支持三种方式的授权。

  第一种,subject.hasRole(“admin”);主体中有admin权限?

Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {// 执行有权限的操作
} else {// 执行无权限的操作
}

  第二种,<shiro:hasRole name=’’ > JSP页面的标签?

# 刚开始接触 Web 的时候,我只会写 JSP 页面。
<shiro:hasRole name="admin">
<!-- 有权限 -->
</shiro:hasRole>

  第三种,学会使用注解之后进常用的。

# 注解式:通过在执行的Java方法上放置相应
@RequiresRoles("admin")
public void hello() {//  执行有权限的操作
}

3.2、@RequiresRoles 和 @RequiresPermissions 注解不生效。

  1. 上边,刚刚说过授权的第三种方式使用注解,但是注解必须必须要使用相应的bean才能生效。
  2. 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证,配置以下两个bean(DefaultAdvisorAutoProxyCreatorAuthorizationAttributeSourceAdvisor)。
# Shiro 权限注解要生效,必须配置 Spring AOP 通过设置 Shiro 的 SecurityManager 进行权限验证。
=================  注解的方式加入Bean ======================
@Beanpublic DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();advisorAutoProxyCreator.setProxyTargetClass(true);            // 开启代理return advisorAutoProxyCreator;
}@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());       // 配置安全管理器。return authorizationAttributeSourceAdvisor;
}
=================  配置文件的方式加入 Bean  ==================
<!-- 开启Shiro Spring AOP权限注解的支持;<aop:config proxy-target-class="true">表示代理类。 -->
<aop:config proxy-target-class="true">
<!-- 生命周期 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/><!-- 注解方式出现异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  <property name="exceptionMappings">  <props>  <prop key="org.apache.shiro.authz.UnauthorizedException">shiro-test/refuse</prop></props>  </property>
</bean>
<!-- 认证用户的注解管理 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"><property name="proxyTargetClass" value="true"/>  <bean><!-- 授权用户的注解管理 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"><property name="securityManager" ref="securityManager"/>
</bean>
### 拦截异常 。
@ExceptionHandler({UnauthorizedException.class})
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public ModelAndView processUnauthenticatedException(NativeWebRequest request, UnauthorizedException e) {  ModelAndView mv = new ModelAndView();  mv.addObject("exception", e);  mv.setViewName("unauthorized");  return mv;
}

3.3、Shiro 的注解。

  1. 注解既可以用在 controller 中,也可以用在 service 中使用。
  2. 建议将shiro注解放在 controller 中,因为如果 service 层使用了spring的事物注解,那么 shiro 注解将无效。

@RequiresAuthentication
表示当前 Subject 已经通过 login 进行了身份验证;即 Subject.isAuthenticated() 返回true。

@RequiresUser
表示当前 Subject 已经身份验证或者通过记住我登录的。

@RequiresGuest
表示当前 Subject 没有身份验证或通过记住我登录过,即是游客身份。

@RequiresRoles(value={“admin”, “user”}, logical= Logical.AND)
@RequiresRoles(value={“admin”})
@RequiresRoles({“admin“})
表示当前 Subject 需要角色 admin 和 user。

@RequiresPermissions (value={“user:create”, “user:delete”}, logical= Logical.OR)
表示当前 Subject 需要权限 user:create 或 user:delete。

3.4、unauthorizedUrl 无效。

  • <property name=“unauthorizedUrl” value="/unauthorized.html"/>
  • shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");

我们在测试之前,发现都起作用,但是在 SSM 框架整合之后,抛出异常,并没有跳转到无权限页面。原因是因为 页面的跳转交给springMVC来控制,权限认证不通过, SpringMVC 抛出了异常。
【方法一:注册 Bean SimpleMappingExceptionResolver 设置异常对应的 url,url 需要在 Controller 中指定

@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();Properties properties = new Properties();/*未授权处理页*/properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/unauthor.html");/*身份没有验证*/properties.setProperty("org.apache.shiro.authz.UnauthenticatedException", "/login.html");resolver.setExceptionMappings(properties);return resolver;}
  • 亲测可以。

    【方法二:自定义异常类 Reslover 捕捉异常,如果异常为无权限异常就手动就是转发到无权页面。
1、首先设置异常的捕获类,
public class MyExceptionResolver implements HandlerExceptionResolver{public ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response, Object handler, Exception e) {//  如果是shiro无权操作,因为shiro 在操作auno 等一部分不进行转发至无权限urlif(e instanceof UnauthorizedException){ModelAndView mv = new ModelAndView("unauthor");return mv;}e.printStackTrace();ModelAndView mv = new ModelAndView("unauthor");mv.addObject("exception", e.toString().replaceAll("\n", "<br/>"));return mv;}
}
2. 自定义异常处理
<bean id="exceptionResolver" class="cn.chao.formyself.resolver.MyExceptionResolver"></bean>

3.5、AJAX 请求,提示无角色无权限。

在上面的异常处理中,我们将判断一个请求,是否拥有角色的权限,无没有权限的话,则跳转到了无权限的页面中,那么我们要使用 AJAX 请求,返回的 error:function() 中应该是一个没有权限的提示信息。

【方法一:仍然使用第一种抛出异常的 Bean 。】

@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();Properties properties = new Properties();/*未授权处理页*/properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/访问方法判断是否是 AJAX 处理");/*身份没有验证*/properties.setProperty("org.apache.shiro.authz.UnauthenticatedException", "/login.html");resolver.setExceptionMappings(properties);return resolver;}

【方法二:配置文件结合 Controller 层的代码判断】

配置异常的拦截器
<!-- shiro 为集成 springmvc 拦截异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><property name="exceptionMappings" ><props><!-- 这里可以配置 N 多个 错误异常转发 --><prop key="org.apache.shiro.authz.AuthorizationException">redirect:/401</prop></property>
</bean>
异常拦截器将异常重定向到了 RequestMapping 401 的 controller 中
@RequestMapping("/401")
public String authorizationException(ModelMap modelMap,HttpServletRequest request){String requestType = request.getHeader("x-Requested-With");// AJAX 请求if(requestType != null && requestType.equals("XMLHttpRequest")){return "redirect:ajax401";          // 我在这里抛出的是权限的异常,判断为 AJAX 的请求方式,这里调用 RequestMapping("ajax401") 的方法,返回String 类型字符串,提示没有数据。}else{return "redirect:syn401";            // 方法体直接放回 无权限页面。}
}

SpringBoot 项目 Shiro 的实现相关推荐

  1. 在 SpringBoot 项目中,Spring Security 和 Shiro 该如何选择?

    点击上方 好好学java ,选择 星标 公众号重磅资讯,干货,第一时间送达 今日推荐:推荐19个github超牛逼项目!个人原创100W +访问量博客:点击前往,查看更多 要知道Shiro和Sprin ...

  2. springboot项目中使用shiro 自定义过滤器和token的方式___shiro使用token登录流程

    springboot项目中使用shiro 自定义过滤器和token的方式 实现步骤主要是以下几步: 1. 在项目中导入maven依赖 <dependency><groupId> ...

  3. springboot配置shiro多项目实现session共享的详细步骤

    springboot配置shiro多项目实现session共享的详细步骤 公司需要这样的需求: 有两个项目master 主项目.suiteone 项目,两个项目各自由shiro 安全框架管理,当不能登 ...

  4. SpringBoot整合Shiro搭建登录注册认证授权权限项目模板

    主要内容: 1 SpringBoot整合Shiro安全框架; 2 Shiro主要学习内容总结;(执行流程.主要对象接口.注意事项等) 3 Redis实现对权限信息缓存; ! 温馨提示: 想要快速搭Sh ...

  5. springboot+jwt+shiro+vue+elementUI+axios+redis+mysql完成一个前后端分离的博客项目(笔记,帮填坑)

    根据B站up主MarkerHub视频制作的一个笔记 我的博客 B站博主链接: https://www.bilibili.com/video/BV1PQ4y1P7hZ?p=1 博主的开发文档: http ...

  6. SpringBoot整合Shiro安全框架完整实现

    目录 一.环境搭建 1. 导入shiro-spring依赖 2. 编写首页及其controller 3. 编写shiro配置类 二.Shiro实现登录拦截 1. 编写页面及其controller 2. ...

  7. 这 5 个能挣钱的 SpringBoot 项目,真TMD香!

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:又一程序员进了ICU:压垮一个家庭,一张结算单就够 个人原创100W+访问量博客:点击前往,查看更多 不得不佩服 ...

  8. SpringBoot+MyBatis+Shiro 搭建杂谈

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:用好Java中的枚举,真的没有那么简单!个人原创+1博客:点击前往,查看更多 链接:https://www.cn ...

  9. SpringBoot整合Shiro实现登录认证和授权CHCache

    文章目录 一. springboot实现普通登录 1 添加依赖 2 编写配置文件 3 新建实体类和mapper 4 编写业务层代码 5 编写控制器 6 编写启动类 7 编写登录页面和主页面 二. sp ...

最新文章

  1. 性能测试工具系列(一):性能测试工具对比分析
  2. 基于上一篇AS项目依赖库问题的优化解决方案
  3. 防止API被恶意调用,一般有哪些方法?
  4. jquey的parent()和parents()的区别
  5. 点击按钮抓不到页面的参数
  6. linux格式化外接硬盘命令,linux格式化硬盘命令
  7. Java 12字符串方法
  8. aliyun gradle 代理_gradle:现代高效的java构建工具
  9. openmeetings(开源视频会议系统)的详细安装步骤 (windows版)
  10. android 里程计算器,里程计算器
  11. 外国人申请在中国永久居留服务指南(中英文)
  12. 我的世界服务器修改地图,我的世界如何修改地图?
  13. 重装系统(win10企业版)
  14. spring cloud NetFlix 学习笔记
  15. opencv中的split函数
  16. Java实现 蓝桥杯 算法提高 成绩排名
  17. 专科学游戏建模好找工作嘛?
  18. 机械CAD设计中如何快速创建孔轴投影?
  19. fastlane自动化打包ipa并发布到firim或者蒲公英
  20. 电商网站运营之道:提升商品销量的新玩法

热门文章

  1. 概率论-一维随机变量及其分布思维导图
  2. JDK8 下载与安装教程,超简单版(Windows)
  3. 在Linux上安装JDK8-教程
  4. 精美中文简历LaTex模板集锦
  5. python基础——类型转换
  6. 中后台管理系统之登录流程
  7. 实体 联系 模型mysql_实体关系模型和关系模型之间有什么区别?
  8. 积微成巨(1)--collect
  9. 【金猿信创展】恒生电子——全栈式信创解决方案,助力金融信创行稳致远
  10. jieba库的安装与使用方法