点击蓝色“程序猿DD”关注我

回复“资源”获取独家整理的学习资料!

写在前面

在一款应用的整个生命周期,我们都会谈及该应用的数据安全问题。用户的合法性与数据的可见性是数据安全中非常重要的一部分。但是,一方面,不同的应用对于数据的合法性和可见性要求的维度与粒度都有所区别;另一方面,以当前微服务、多服务的架构方式,如何共享Session,如何缓存认证和授权数据应对高并发访问都迫切需要我们解决。Shiro的出现让我们可以快速和简单的应对我们应用的数据安全问题.>>阿里云8月最新优惠,点击查看<<

Shiro介绍

Shiro简介

这个官网解释不抽象,所以直接用官网解释:Apache Shiro™是一个强大且易用的 Java 安全框架,可以执行身份验证、授权、加密和会话管理等。基于 Shiro 的易于理解的API,您可以快速、轻松地使任何应用程序变得安全(从最小的移动应用到最大的网络和企业应用)。

谈及安全,多数 Java 开发人员都离不开 Spring 框架的支持,自然也就会先想到 Spring Security,那我们先来看二者的差别

Shiro Spring Security  
简单、灵活 复杂、笨重  
可脱离Spring 不可脱离Spring  
粒度较粗 粒度较细  

虽然 Spring Security 属于名震中外 Spring 家族的一部分,但是了解 Shiro 之后,你不会想 “嫁入豪门”,而是选择追求「诗和远方」冲动。

横看成岭侧成峰,远近高低各不同 (依旧是先了解概念就好)

远看 Shiro 看轮廓

Subject

它是一个主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有 Subject 都绑定到 SecurityManager,与 Subject 的所有交互都会委托给SecurityManager;可以把 Subject 认为是一个门面;SecurityManager 才是实际的执行者

SecurityManager

安全管理器;即所有与安全有关的操作都会与 SecurityManager 交互;且它管理着所有 Subject;可以看出它是 Shiro 的核心,它负责与后边介绍的其他组件进行交互,如果学习过 SpringMVC,你可以把它看成 DispatcherServlet前端控制器

Realm

域,Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色/权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。

近看 Shiro 看细节

看图瞬间懵逼?别慌,会为你拆解来看,结合着图看下面的解释,这不是啥大问题,且看:

Subject

主体,可以看到主体可以是任何可以与应用交互的 “用户”

SecurityManager

相当于 SpringMVC 中的 DispatcherServlet;是 Shiro 的心脏;所有具体的交互都通过 SecurityManager 进行控制;它管理着所有 Subject、且负责进行认证和授权、及会话、缓存的管理

Authenticator

认证器,负责主体认证的,这是一个扩展点,如果用户觉得 Shiro 默认的不好,可以自定义实现;需要自定义认证策略(Authentication Strategy),即什么情况下算用户认证通过了

Authrizer

授权器,或者访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能

Realm

可以有 1 个或多个 Realm,可以认为是安全实体数据源,即用于获取安全实体的;可以是JDBC实现,也可以是LDAP实现,或者内存实现等等;由用户提供;注意:Shiro 不知道你的用户/权限存储在哪及以何种格式存储;所以我们一般在应用中都需要实现自己的Realm

SessionManager

如果写过 Servlet 就应该知道 Session 的概念,Session 需要有人去管理它的生命周期,这个组件就是 SessionManager;而Shiro 并不仅仅可以用在 Web 环境,也可以用在如普通的 JavaSE 环境、EJB等环境;所以,Shiro 就抽象了一个自己的Session 来管理主体与应用之间交互的数据;这样的话,比如我们在 Web 环境用,刚开始是一台Web服务器;接着又上了台EJB 服务器;这时又想把两台服务器的会话数据放到一个地方,我们就可以实现自己的分布式会话(如把数据放到Memcached 服务器)

SessionDAO

DAO大家都用过,数据访问对象,用于会话的 CRUD,比如我们想把 Session 保存到数据库,那么可以实现自己的SessionDAO,通过如JDBC写到数据库;比如想把 Session 放到 Memcached 中,可以实现自己的 Memcached SessionDAO;另外 SessionDAO 中可以使用 Cache 进行缓存,以提高性能;

CacheManager

缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能

Cryptography

密码模块,Shiro提高了一些常见的加密组件用于如密码「加密/解密」的

注意上图的结构,我们会根据这张图来逐步拆分讲解,记住这张图也更有助于我们理解 Shiro 的工作原理,所以依旧是打开两个网页一起看就好喽

搭建概览

多数小伙伴都在使用 Spring Boot, Shiro 也很应景的定义了 starter,做了更好的封装,对于我们来说使用起来也就更加方便,来看选型概览

序号 名称 版本  
1 Springboot 2.0.4  
2 JPA 2.0.4  
3 Mysql 8.0.12  
4 Redis 2.0.4  
5 Lombok 1.16.22  
6 Guava 26.0-jre  
7 Shiro 1.4.0  

使用 Spring Boot,大多都是通过添加 starter 依赖,会自动解决依赖包版本,所以自己尝试的时候用最新版本不会有什么问题,比如 Shiro 现在的版本是 1.5.0 了,整体问题不大,大家自行尝试就好

添加 Gradle 依赖管理

大体目录结构

application.yml 配置

基本配置

你就让我看这?这只是一个概览,先做到心中有数,我们来看具体配置,逐步完成搭建

其中 shiroFilter bean 部分指定了拦截路径和相应的过滤器,”/user/login”, ”/user”, ”/user/loginout” 可以匿名访问,其他路径都需要授权访问,shiro 提供和多个默认的过滤器,我们可以用这些过滤器来配置控制指定url的权限(先了解个大概即可):

配置缩写 对应的过滤器 功能  
anon AnonymousFilter 指定url可以匿名访问  
authc FormAuthenticationFilter 指定url需要form表单登录,默认会从请求中获取username、password,rememberMe等参数并尝试登录,如果登录不了就会跳转到loginUrl配置的路径。我们也可以用这个过滤器做默认的登录逻辑,但是一般都是我们自己在控制器写登录逻辑的,自己写的话出错返回的信息都可以定制嘛。 
authcBasic BasicHttpAuthenticationFilter 指定url需要basic登录  
Logout LogoutFilter 登出过滤器,配置指定url就可以实现退出功能,非常方便  
noSessionCreation NoSessionCreationFilter 禁止创建会话  
perms PermissionsAuthorizationFilter 需要指定权限才能访问  
port PortFilter 需要指定端口才能访问  
rest HttpMethodPermissionFilter 将http请求方法转化成相应的动词来构造一个权限字符串,这个感觉意义不大,有兴趣自己看源码的注释  
roles RolesAuthorizationFilter 需要指定角色才能访问  
ssl SslFilter 需要https请求才能访问  
user UserFilter 需要已登录或“记住我”的用户才能访问  

数据库表设计

数据库表设计请参考 entity package下的 bean,通过@Entity 注解与 JPA 的设置自动生成表结构 (你需要简单的了解一下 JPA 的功能)。

我们要说重点啦~~~

身份认证

身份认证是一个证明 “李雷是李雷,韩梅梅是韩梅梅” 的过程,回看上图,Realm 模块就是用来做这件事的,Shiro 提供了 IniRealm,JdbcReaml,LDAPReam等认证方式,但自定义的 Realm 通常是最适合我们业务需要的,认证通常是校验登录用户是否合法。

新建用户 User

定义 Repository

编写UserController:

自定义 Realm

自定义 Realm,主要是为了重写 doGetAuthenticationInfo(…)方法

这些代码我需要做一个说明,你可能也满肚子疑惑:

  1. 这段代码怎么应用了 shiro?

  2. controller 是怎么调用到 custom realm 的?

  3. 重写的 doGetAuthenticationInfo(…) 方法目的是什么?

认证流程说明

用户访问/user/login 路径,生成 UsernamePasswordToken, 通过SecurityUtils.getSubject()获取Subject(currentUser),调用 login 方法进行验证,让我们跟踪一下代码,瞧一瞧就知道自定义的CustomRealm怎样起作用的,一起来看源码:

到这里我们要停一停了,请回看 Shiro 近景图,将源码追踪路径与其对比,是完全一致的

授权

身份认证是验证你是谁的问题,而授权是你能干什么的问题,

产品经理:申购模块只能科室看程序员:好的产品经理:科长权限大一些,他也能看申购模块程序员:好的(黑脸)产品经理:科长不但能看,还能修改数据程序员:关公提大刀,拿命来

作为程序员,我们的宗旨是:「能动手就不吵吵」; 硝烟怒火拔地起,耳边响起驼铃声(Shiro):「放下屠刀,立地成佛」授权没有那么麻烦,大家好商量…

整个过程和身份认证基本是一毛一样,你对比看看

角色实体创建

涉及到授权,自然要和角色相关,所以我们创建 Role 实体:

新建 Role Repository

定义权限实体 Permission

定义 Permission Repository

建立用户与角色关系

其实可以通过 JPA 注解来制定关系的,这里为了说明问题,以单独外键形式说明

建立角色与权限关系

编写 UserController

@RequiresPermissions("user:list:view") 注解说明具有用户:列表:查看权限的才可以访问),官网明确给出权限定义格式,包括通配符等,我希望你自行去查看

自定义 CustomRealm (主要重写 doGetAuthorizationInfo) 方法:

与认证流程如出一辙,只不过多了用户,角色,权限的关系罢了

授权流程说明

这里通过过滤器(见Shiro配置)和注解二者结合的方式来进行授权,和认证流程一样,最终会走到我们自定义的 CustomRealm 中,同样 Shiro 默认提供了许多注解用来处理不同的授权情况

注解 功能  
@RequiresGuest 只有游客可以访问  
@RequiresAuthentication 需要登录才能访问  
@RequiresUser 已登录的用户或“记住我”的用户能访问  
@RequiresRoles 已登录的用户需具有指定的角色才能访问  
@RequiresPermissions 已登录的用户需具有指定的权限才能访问(如果不想和产品经理华山论剑,推荐用这个注解) 

授权官网给出明确的授权策略与案例,请查看:http://shiro.apache.org/permissions.html

上面的例子我们通过一直在通过访问 Mysql 获取用户认证和授权信息,这中方式明显不符合生产环境的需求

Session会话管理

做过 Web 开发的同学都知道 Session 的概念,最常用的是 Session 过期时间,数据在 Session 的 CRUD,同样看上图,我们需要关注 SessionManager 和 SessionDAO 模块,Shiro starter 已经提供了基本的 Session配置信息,我们按需在YAML中配置就好(官网https://shiro.apache.org/spring-boot.html 已经明确给出Session的配置信息)

Key Default Value Description  
shiro.enabled true Enables Shiro’s Spring module  
shiro.web.enabled true Enables Shiro’s Spring web module  
shiro.annotations.enabled true Enables Spring support for Shiro’s annotations  
shiro.sessionManager.deleteInvalidSessions true Remove invalid session from session storage  
shiro.sessionManager.sessionIdCookieEnabled true Enable session ID to cookie, for session tracking  
shiro.sessionManager.sessionIdUrlRewritingEnabled true Enable session URL rewriting support  
shiro.userNativeSessionManager false If enabled Shiro will manage the HTTP sessions instead of the container  
shiro.sessionManager.cookie.name JSESSIONID Session cookie name  
shiro.sessionManager.cookie.maxAge -1 Session cookie max age  
shiro.sessionManager.cookie.domain null Session cookie domain  
shiro.sessionManager.cookie.path null Session cookie path  
shiro.sessionManager.cookie.secure false Session cookie secure flag  
shiro.rememberMeManager.cookie.name rememberMe RememberMe cookie name  
shiro.rememberMeManager.cookie.maxAge one year RememberMe cookie max age  
shiro.rememberMeManager.cookie.domain null RememberMe cookie domain  
shiro.rememberMeManager.cookie.path null RememberMe cookie path  
shiro.rememberMeManager.cookie.secure false RememberMe cookie secure flag  
shiro.loginUrl /login.jsp Login URL used when unauthenticated users are redirected to login page  
shiro.successUrl / Default landing page after a user logs in (if alternative cannot be found in the current session) 
shiro.unauthorizedUrl null Page to redirect user to if they are unauthorized (403 page)  

分布式服务中,我们通常需要将Session信息放入Redis中来管理,来应对高并发的访问需求,这时只需重写SessionDAO即可完成自定义的Session管理

整合Redis

重写SessionDao

查看源码,可以看到调用默认SessionManager的retriveSession方法,我们重写该方法,将Session放入HttpRequest中,进一步提高session访问效率

向ShiroConfig中添加配置

其实在概览模块已经给出代码展示,这里单独列出来做说明:

至此,将 session 信息由 redis 管理功能就这样完成了

缓存管理

应对分布式服务,对于高并发访问数据库权限内容是非常低效的方式,同样我们可以利用Redis来解决这一问题,将授权数据缓存到Redis中

新建 RedisCache

新建 RedisCacheManager

至此,我们不用每次访问 Mysql DB 来获取认证和授权信息,而是通过 Redis 来缓存这些信息,大大提升了效率,也满足分布式系统的设计需求

总结

回复公众号 「demo」获取 demo 代码。这里只是梳理了Springboot整合Shiro的流程,以及应用Redis最大化利用Shiro,Shiro的使用细节还很多,官网说的也很明确,带着上面的架构图来理解Shiro会事半功倍,感觉这里面的代码挺多挺头大的?那是你没有自己动手去尝试,结合官网与 demo 相信你会对 Shiro 有更好的理解,另外你可以理解 Shiro 是 mini 版本的 Spring Security,我希望以小见大,当需要更细粒度的认证授权时,也会对理解 Spring Security 有很大帮助,点击文末「阅读原文」,效果更好

落霞与孤鹜齐飞 秋水共长天一色,产品经理和程序员一片祥和…

我们开小店啦,新人9折券限量领取

留言交流不过瘾?添加微信:zyc_enjoy

根据指引加入各种主题讨论群

每日一问

今日问题

(留言说说你的答案吧,明日推文公布答案)

昨日答案:选A

除了图形B,其他图形都有黑色边框

除了图形C,其他图形都是方的

除了图形D,其他图形都是红的

除了图形E,其他图形都是大的

只有图形A集合了大部分特点,却没有任何一点与众不同,A才是与众不同的!

不为最先不耻最后,中庸之道亦在其中

(昨日问题可在昨日推文的文末查看)

推荐阅读

  • 你必须收藏的Github技巧

  • 开发部署提速8倍!这款IDE插件了解一下?

  • 攻破MySQL性能瓶颈必知的调优技巧

  • 如何模拟将CPU、IO打满?

  • Spring Cloud Alibaba 发布第一个正式版本,顺利完成孵化!

来星球聊聊技术人的斜杠生活

点一点“阅读原文”小惊喜在等你

不用 Spring Security 可否?试试这个小而美的安全框架相关推荐

  1. springsecurity sessionregistry session共享_不用 Spring Security 可否?试试这个小而美的安全框架...

    写在前面 在一款应用的整个生命周期,我们都会谈及该应用的数据安全问题.用户的合法性与数据的可见性是数据安全中非常重要的一部分.但是,一方面,不同的应用对于数据的合法性和可见性要求的维度与粒度都有所区别 ...

  2. Spring Security OAuth2.0认证授权知识概括

    Spring Security OAuth2.0认证授权知识概括 安全框架基本概念 基于Session的认证方式 Spring Security简介 SpringSecurity详解 分布式系统认证方 ...

  3. Spring Security 5.0.x 参考手册 【翻译自官方GIT-2018.06.12】

    源码请移步至: https://github.com/aquariuspj/spring-security/tree/translator/docs/manual/src/docs/asciidoc ...

  4. 基于 Spring Security 的开源统一角色访问控制系统 URACS

    URACS Java语言开发的统一角色访问控制系统(Unified Role Access Control System),基于Spring Security 3实现的权限控制系统 程序框架版本说明: ...

  5. gwt格式_使用Spring Security保护GWT应用程序的安全

    gwt格式 在本教程中,我们将看到如何将GWT与Spring的安全模块(即Spring Security)集成. 我们将看到如何保护GWT入口点,如何检索用户的凭据以及如何记录各种身份验证事件. 此外 ...

  6. Spring Security第1部分–具有数据库的简单登录应用程序

    什么是Spring Security? Spring Security是一个提供安全解决方案的框架,可在Web请求级别和方法级别上处理身份验证和授权. Spring安全性通过两种方式处理安全性. 一种 ...

  7. 使用Spring Security保护GWT应用程序

    在本教程中,我们将看到如何将GWT与Spring的安全模块(即Spring Security)集成在一起. 我们将看到如何保护GWT入口点,如何检索用户的凭据以及如何记录各种身份验证事件. 此外,我们 ...

  8. Spring Security(安全框架)

    一.概念 (1)Spring Security是一个高度自定义的安全框架.利用Spring IoC/DI和AOP功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作. ( ...

  9. Spring Security(安全)

    在web开发中,安全第一位!拦截器.过滤器.安全框架 Spring Security Spring Security是针对springboot项目的安全框架,也是Spring Boot低层安全模块默认 ...

最新文章

  1. iframe几种常用代码片段
  2. jQuery 1.9 移除了 $.browser 的替代方法
  3. 9 行代码提高少样本学习泛化能力,代码已开源
  4. OVS datapath结构图(四十六)
  5. si24r1程序_简要分析SI24R1替代兼容NRF24L01P
  6. 软件项目管理课后题下载【共5个章(1、3、4、5、6)】
  7. 解决编译.spec:rpm build with: fg: no job control报错
  8. mysql备份的sql语句_Mysql主从备份和SQL语句的备份
  9. Linux Kernel中irq handler, softirq handler 和 tasklet
  10. xcode,cocoa开发:如何使用第三方的dylib
  11. 电脑桌面上文件夹图标右上角有双箭头
  12. python3网络爬虫开发实战6.3爬取微博处理since_id
  13. VMware Workstation左侧不见了,左侧菜单栏不见了
  14. strpos函数 mysql_php常用字符串查找函数strstr()与strpos()实例分析
  15. “幽灵刹车”困扰特斯拉
  16. java获取pdf文件首页图片,用来当做封面
  17. 常见的网络状态码(HTTP状态码)
  18. 【千里之行,始于足下】大数据高频面试题——Hive篇(一)
  19. 当当笔试题(有n个人成一圈,顺序排号(编号为1到n),从第一个人开始报数1到3报数),凡报到3的人出圈子,从下个人开始继续报数,直到最后一个人,问最后留下在是第几号?)
  20. project标签爆红:“unexpected markup <!d (position: START_DOCUMENT seen \r\n<!d... @2:4) maven依赖报错

热门文章

  1. Pulsar 社区周报| 2020-12-12 ~ 2020-12.18
  2. 解密小米生态链:从构建到定义产品
  3. 腾讯十大最受欢迎的开源项目!
  4. 百度飞桨—PM2.5预测
  5. H3C和华为配置端口聚合的问题
  6. 无论是狗粮还是降落伞,反正WeLink来了……
  7. 电脑 | 更新后显示器无法实现夜间模式
  8. 20个VC开发小技巧
  9. 你该用什么的美剧学英语?
  10. 剪刀石头布java_java编写剪刀石头布游戏