这个框架已经开源到码云上面,介绍比较详细,链接:https://git.oschina.net/tywo45/t-io,由于官方介绍中的入门程序客户端和服务端都是用的java写的,而且是用简单的自定义TCP协议进行通信的,也有一个websocket协议的列子,感觉有点复杂,不好入门。就想着使用javascript来做客户端,t-io做服务端,采用websocket协议搞一个helloworld。
首先,t-io框架简单说就是封装一下些个:
所以我们收到客户端发来的websocket协议的包,在服务端就要做对应的解包,那我们还要了解websocket包的结构和通信建立的过程:
①握手阶段:
客户端和服务器建立TCP连接之后,客户端发送握手请求,随后服务器发送握手响应即完成握手阶段。如下:
客户端握手请求类似如下:
服务器的握手响应类似如下:
|
|
②握手成功后开始发送数据帧
这是Websocket的数据传输协议,聊天信息一般会按照这个协议的规则来传输,下图中的一整个东西称为一个数据帧,数据帧的成帧和解析是处理这个协议时最麻烦的一部分了。具体这个表怎么看可以参照
|
|
整体的编写和框架自带的Helloworld程序模式一致,需要改变的就是encode()编码方法和decode()解码方法,因为需要根据websocket协议来。
收到消息后先解码,再判断包的类型,交给响应类型的handler。发送消息先编码。
①握手
decode()解码方法:
由于客户端收到的第一个包是握手包,所以:
|
|
握手包的Handler,返回握手响应包,让客户端知道握手成功,可以进行数据传输了,:
|
|
encode()编码方法:
上面在握手包的handler中,调用了send方法,发送了一个握手响应包,所以要在编码的时候先判断是否是握手响应包,对其编码:
|
|
握手响应包的编码
②数据包
decode()解码方法:
上面握手成功的时候会在BarrageSessionContext中保存握手的情况。
|
|
数据包的handler:
|
|
这个收到消息后的处理是,发送收到的消息到客户端。
encode()编码方法:
|
|
|
|
websocket协议的服务器的处理流程大致是上面这个流程,但是代码我只贴了关键部分,完整的代码可以去我的码云上下载。
|
|
最好是下载程序下来,打上断点,debug去跟一下,每一步包做了那些处理,变成了什么样子,传输的二进制数据转换成字符串是甚么样子等等。
·······················································································································································
此项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus
·······················································································································································
]]>平时在建对象表的时候都会有最后修改时间,最后修改人这两个字段,对于这些大部分表都有的字段,每次在新增和修改的时候都要考虑到这几个字段有没有传进去,很麻烦。mybatisPlus有一个很好的解决方案。也就是公共字段自动填充的功能。一般满足下面条件的字段就可以使用此功能:
这个字段是大部分表都会有的。
这个字段的值是固定的,或则字段值是可以在后台动态获取的。
常用的就是last_update_time,last_update_name这两个字段。
导包:只需要注意的一点就是,mybatisPlus是在2.0.6版本才支持的更新数据公共字段自动填充,之前都是只支持新增数据的时候可以使用。
如果是之前配置过MybatisPlus的同学只需要添加以下几个步骤:
insertFill()
新增数据时需要填充的字段设置和updateFill()
更新数据的时候需要填充的字段设置这两个方法:
|
|
注意:getValue()方法的参数是pojo类里面的变量(驼峰的命名方式)。
|
|
也就是将刚刚写的公共字段填充的设置设置到MP全局配置的对象中。
|
|
原因:因为调用更新和插入的方法时,会验证你所传的属性是否为空,来判断是否该更新和插入这个属性,这个就和公共字段自动填充相冲突了,所以需要这个注解来标识此属性不需要验证。不然在插入的时候就会填充失败。
如果之前没有使用过MbatisPlus,可以出门左转,链接:之前写过的一个博文,里面涉及到MybatisPlus的基础使用配置
|
|
|
|
本来是打算创建人和创建时间,也使用这种方法处理的,最后发现,如果将这两个字段也忽略为空的判断,也就是加上validate=FieldStrategy.NOT_EMPTY
,在更新数据的时候会将创建人和创建时间一起更新了,不传的话就会更新为空。所以本人觉得这个mybatisPlus这个公共字段自动填充功能是不错,但是在正真用的上的需求上面使用的时候还不够完善。
·······················································································································································
此项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus
·······················································································································································
]]>在windows下安装的redis,在安装目录找到redis.windows.conf
文件,修改以下字段(按实际情况设置):
|
|
slowlog-log-slower-than:是配置需要日志记录的命令执行时间,单位是微秒,也就是说配置为100,会记录命令执行时间为0.1ms以上的记录。如果设置为0,就会记录所有执行过的命令。
slowlog-max-len:是配置日志记录的条数,因为这个日志也是存储在内存中的,所以不需要担心记录日志会影响性能,但是会消耗一定内存。
完成对这些信息的获取主要还是利用redis的一些命令,如果是win系统下安装的redis,在安装目录运行redis-cli.exe
这个文件,输入info
,再回车,就可以看到输出很多字段的参数,部分具体参数对应的意思如下:
上面是命令窗的方式,使用java的话,我们就是借助jedis这个框架来帮我们完成:
|
|
这样输出的都是和控制台一样的字符串,所以还需要sevice来对数据进行封装:
|
|
上面我只是贴了部分核心代码,想具体去了解的可以去下载我的项目跑一下。
由于这个没有什么难度,只是就只是贴了些代码。后续也会一直更新,一步步将这个系统完善起来。
·······················································································································································
此项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus
·······················································································································································
]]>shiro+redis集成,避免每次访问有权限的链接都会去执行MyShiroRealm.doGetAuthenticationInfo()方法来查询当前用户的权限,因为实际情况中权限是不会经常变得,这样就可以使用redis进行权限的缓存。
实现shiro链接权限的动态加载,之前要添加一个链接的权限,要在shiro的配置文件中添加filterChainDefinitionMap.put(“/add”, “roles[100002],perms[权限添加]”),这样很不方便管理,一种方法是将链接的权限使用数据库进行加载,另一种是通过init配置文件的方式读取。
Shiro 自定义权限校验Filter定义,及功能实现。
Shiro Ajax请求权限不满足,拦截后解决方案。这里有一个前提,我们知道Ajax不能做页面redirect和forward跳转,所以Ajax请求假如没登录,那么这个请求给用户的感觉就是没有任何反应,而用户又不知道用户已经退出了。
控制同一个用户的在线数量。(挤出之前的登录用户)
Shiro 登录后跳转到最后一个访问的页面
在线显示,在线用户管理(踢出登录)。
登录注册密码加密传输。
集成动态验证码。
记住我的功能。关闭浏览器后还是登录状态。
·······················································································································································
此项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus
·······················································································································································
session是大家比较熟悉的功能,因为HTTP协议是无状态的,网站为了在多个请求之间传递数据就使用了session这个东西,session是存储在网站服务器上的某个地方,比如内存、数据库或者其他的什么东西,在我的配置中是用redis存储的,因为我使用了Shiro的Native Session Manager,替代了Tomcat本身的Session Manager,并且为Shiro的Native Session Manager配置了redis的SessionDAO,当然这个我是直接使用的一个开源插件,里面已经帮我们很好的实现了cacheManager,sessionManager,redisSessionDAO这些。直接使用就可以了。
shiro_redis插件地址:http://www.oschina.net/p/shiro-redis
所以所有的session会话都是缓存在redis里面的。对session的增删改查都是在操作redis数据库来完成。所以如果将redis进行集群的话,session会话也就会达到集群的目的。后面我专门写博客来分享。
在这种情况下服务器的Session就存储在redis里面,如果某个Session过期(比如关闭了浏览器或者超时),此条Session就会从redis里面永久删除,下次的请求将不能使用Session里面的数据。所以说即使有些url设置的是”user”级别的(也就是说不用登录即可访问,只须设置了rememberMe),但是如果这些url使用了Session里面的数据,就会抛出异常,因为此时这个用户对应的Session已经不存在了。
当浏览一个网站的时候,网站返回给你一个Session Cookie和一个RememberMe Cookie,Session Cookie很好理解,就是为了此次的对话,一旦关闭了浏览器或者超时了Session Cookie就没用了。但是RememberMe Cookie不太一样,Shiro默认的RememberMe Cookie的时长是一年,所以不用担心这个Cookie的情况。RememberMe Cookie实际就是Shiro把这个用户的信息加密一下放到cookie里面,下次就可以根据这个cookie来进行判断这是哪个用户。
主要讲下shiro的rememberMe cookie。在shiro中有一个类实现了rememberMe功能, org.apache.shiro.web.mgt.CookieRememberMeManager 。在登录时,代码也很简单:
|
|
RememberMe这个参数设置为true后,在登陆的时候就会在客户端设置remenberme的相应cookie。下次访问带上这个cookie,访问链接为user链接器的,就不需要进行登录验证,直接进入权限验证。下面是完整的处理过程:
这样不需要进入身份验证的拦截器,就直接从cookie中获取到了登录信息。
session整个流程很好理解,我们使用的插件,对session的操作理解可以去看我之前写的在线用户管理和控制在线人数功能,基本都是对session的操作。
https://my.oschina.net/z707z/blog/852189
对于cookie我又下面几点疑惑,忘大神指点:
我在测试的时候,使用了remenberme的功能后,我将登录生成的cookie复制出来,我不管重新登录相同用户多少次,我带上这个cookie访问的时候,还是不会走身份验证这个拦截器。只走权限验证的拦截器,也就是说用户在使用退出登录后。之前的cookie还是有效的。并没有清除。怎么清除cookie。不是所清除客户端的cookie,而是清除服务器记住的cookie序列化文件。
有没有什么好的方法可以防止盗取cookie,进行xss攻击。
网上找了一个思路:
这样处理有一个不好的地方就是:必须要每次用户要再次操作的时候才会发现cookie被盗用,如果被盗用的cookie是用户最后一次操作生成的cookie呐。
我到觉得控制用户登录人数为只能一个人登录一个帐号,还比上面这个方便些,不会反复的生成cookie,写入cookie。但是也不好,没有解决服务器上的cookie没有根据用户的退出而失效的这个问题。
]]>jqGrid :是一个在jquery基础上做的一个表格控件,以ajax的方式和服务器端通信。支持json和xml数据和服务器交互,有很多自定义的功能,具体可以去看文档:http://blog.mn886.net/jqGrid/ 。
MybatisPlus:这个框架是国内的大神编写的,我个人认为这就是一个mybatis的一个增强工具包,好处请大家自行去官方文档查阅,这里就不再赘述了。文档链接:http://mp.baomidou.com/docs/index.html 。
如果之前没有用过的同学也可以看我的项目来学到这两个框架的实际用法。
·······················································································································································
此项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus
·······················································································································································
我是在之前项目上来进行开发的,所以已经完成了mybatisPlus的搭建,具体mybatisPlus的配置可以去看我之前美女图片爬虫的那篇博文。
下面我就以角色表的分页排序为例:
由于数据层mybatisPlus已经对分页进行了封装,直接在controller层调用分页方法:
|
|
FrontPage对象是用来接受前台jqGrid传来的对象。
|
|
CustomPage对象是我封装的,由于jqGrid和MybatisPlus中的怕个对象字段名称不一样,所以用此对象来过度,就是传入mybatisPlus的page对象,转换成jqGrid的怕个对象,再封装成json对象传到前台。
|
|
这个controller测试链接:http://127.0.0.1:8080/role/getRoleListWithPager?_search=false&nd=1489983253884&rows=15&page=1&sidx=&sord=asc
后面的参数含义,对照FrontPage.java的字段。
访问这个controller得到下面的json串:
|
|
对应字段意思,对照CustomPage.java中的字段。
前台加载表单的js代码:
|
|
显示效果
这个分页查询是mybatisPlus已经写好了,只是针对单表查询,如果是自定义多表查询的话,就需要自己写查询sql语句,自己写mapper.xml文件,自己写mapper接口,自己写service,那怎么使用page类分页呐?
只要在查询的mapper.xml中传入page对象,mybatisPlus就会根据传入的page对象拦截生成对应的查询sql语句。所以如果是多表查询也可以自己实现service ,mappe接口,mapper.xml等来实现多表查询的分页排序等。
实际上面分页的实现后,排序也跟着实现了,再点击表头的某个字段时,jqgrid会发送ajax请求访问分页链接:http://localhost:8080/role/getRoleListWithPager?_search=false&nd=1489984862781&rows=15&page=1&sidx=name&sord=asc 。mybatisPlus会根据传入的page对象拦截sql的生成。达到分页排序的效果。
没传sidx字段的时候:拦截器生成的sql为:SELECT id,name
,type
FROM sys_role LIMIT 0,15
传入sidx字段为name的时候:拦截器生成的sql为:SELECT id,name
,type
FROM sys_role ORDER BY name ASC LIMIT 0,15
这些都是mybatisPlus给我们封装好了的,建议去了解下源码。
这个代码实现就比较简单了,可以直接去我码云上面去查看源码。
·······················································································································································
此项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus
·······················································································································································
|
|
代码中注释比较完善,也可以去下载源码查看,这样结合看,跟容易理解,不懂的在评论区留言,看见必回!
|
|
这是在KickoutSessionControlFilter这个拦截器里面做的修改。
现在项目里面的密码整个流程都是以明文的方式传递的。这样在实际应用中是很不安全的,京东,开源中国等这些大公司都有泄库事件,这样对用户的隐私造成巨大的影响,所以将密码加密存储传输就非常必要了。
密码重试次数限制,也是出于安全性的考虑。
shiro本身是有对密码加密进行实现的,提供了PasswordService及CredentialsMatcher用于提供加密密码及验证密码服务。这里我觉得这种过于麻烦,大家有需要可以去看这篇博客:shiro加密解密。
我就是自己实现的EDS加密,并且保存的加密明文是采用password+username的方式,减小了密码相同,密文也相同的问题,这里我只是贴一下,EDS的加密解密代码,另外我还改了MyShiroRealm文件,再查数据库的时候加密后再查,而且在创建用户的时候不要忘记的加密存到数据库。这里就补贴代码了。
|
|
如在1个小时内密码最多重试5次,如果尝试次数超过5次就锁定1小时,1小时后可再次重试,如果还是重试失败,可以锁定如1天,以此类推,防止密码被暴力破解。我们使用redis数据库来保存当前用户登录次数,也就是执行身份认证方法:MyShiroRealm.doGetAuthenticationInfo()的次数,如果登录成功就清空计数。超过就返回相应错误信息。根据这个逻辑,修改MyShiroRealm.java如下:
|
|
我们经常会有用到,当A 用户在北京登录 ,然后A用户在天津再登录 ,要踢出北京登录的状态。如果用户在北京重新登录,那么又要踢出天津的用户,这样反复。又或是需要限制同一用户的同时在线数量,超出限制后,踢出最先登录的或是踢出最后登录的。
第一个场景踢出用户是由用户触发的,有时候需要手动将某个在线用户踢出,也就是对当前在线用户的列表进行管理。
·························································································································································
个人博客:http://z77z.oschina.io/
此项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus
························································································································································
spring security就直接提供了相应的功能;Shiro的话没有提供默认实现,不过可以很容易的在Shiro中加入这个功能。那就是使用shiro强大的自定义访问控制拦截器:AccessControlFilter,集成这个接口后要实现下面这三个方法。
|
|
isAccessAllowed:表示是否允许访问;mappedValue就是[urls]配置中拦截器参数部分,如果允许访问返回true,否则false;
onAccessDenied:表示当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可。
onPreHandle:会自动调用这两个方法决定是否继续处理;
另外AccessControlFilter还提供了如下方法用于处理如登录成功后/重定向到上一个请求:
|
|
比如基于表单的身份验证就需要使用这些功能。
到此基本的拦截器就完事了,如果我们想进行访问的控制就可以继承AccessControlFilter;如果我们要添加一些通用数据我们可以直接继承PathMatchingFilter。
下面就是我实现的访问控制拦截器:KickoutSessionControlFilter:
|
|
将这个自定义的拦截器配置在ShiroConfig.java文件中:
|
|
将这个kickoutSessionControlFilter()注入到shiroFilterFactoryBean中:
|
|
由于我们链接权限的控制是动态存在数据库中的,这个可以去看我之前动态权限控制的博文,所以我们还要在数据库中修改链接的权限,将kickout这个自定义的权限配置在对应的链接上。如下图:
还要编写对应的被踢出的跳转页面:
|
|
到此,第一个场景就实现了,写到这里实际第二个场景的实现思路已经就很明显了,可以通过sessionDAO获取到全部的shiro会话List,然后显示在前端页面,踢出对应用户就可以使用在对应sessionId的session域中设置key为kickout的值为true,上面的KickoutSessionControlFilter就会判断session域中的kickout值,做响应的处理。这里我就先不上代码了,大家可以自己试一试。之后再把代码同步到我的码云上,供大家学习交流。
处理了这个需求后,我发现一个问题,这里有一个前提,我们知道Ajax不能做页面redirect和forward跳转,所以Ajax请求假如没登录,那么这个请求给用户的感觉就是没有任何反应,而用户又不知道用户已经退出了。这个就要对ajax请求做相应的优化,我已经有解决思路了,大家也可以思考下,我也会在下一博提供代码。
还有我接下来会对之前的前端页面进行完善,比如下面是我更新的登录页面:
已经更新到我的码云上面。
]]>如标题有如下两个功能实现:
记住我的功能:通过设置key为“rememberMe”的cookie保存在客户端来完成记住我的功能,下次用户访问指定页面时就不会重新登录,一直到cookie过期后才会重新登录。
GIF格式验证码: ,这个要感谢sojson的博主对这个GIF验证码插件的实现。
此项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus
在ShiroConfig.java中添加如下方法:
|
|
rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cookie的有效时间等等。
rememberMeManager()方法是生成rememberMe管理器,而且要将这个rememberMe管理器设置到securityManager中,如下:
|
|
其实上面的步骤,也就是rememberMe管理器可以不用配置,shiro会使用默认的配置,之所以要配置的目的是为了能够在实际业务环境中自定义其中的参数。
|
|
之前我是将shiro已经实现的UsernamePasswordToken类再封装了一层,最后发现没有必要,直接使用shiro提供的UsernamePasswordToken的类,其中有一个构造函数需要传rememberMe这个参数,也就是shiro为我们已经实现好了,推荐大家去看下UsernamePasswordToken这个类的源码。
|
|
添加一个记住我的单选框,来控制是否需要记住我。
因为getGifCode是获取验证码的链接,所以要配置为anon,不需要权限验证。user权限是配置记住我或认证通过可以访问,所以将/**链接设置为user权限,就可以实现记住我的功能。
注意权限添加的排序。
|
|
生成验证码后,将图片返回到页面,将字符串保存在当前会话的session域中。
这个GIF验证码的生成插件源码在我的项目io.z77z.vcode这个包下面,大家需要的话可以在我的码云上去下载。
|
|
登录的时候判断前台传入的验证码和session中的是否一致。
|
|
到此,我们集成shiro和redis,学习了一下功能的实现:
香蕉硬币点赞走一波啦。。。。。。
]]>之前我们整合Shiro,完成了登录认证和权限管理的实现,登录认证没什么说的,需要实现AuthorizingRealm中的doGetAuthenticationInfo方法进行认证,但是我们在实现doGetAuthorizationInfo权限控制这个方法的时候发现以下两个问题:
第一个问题:我们在ShiroConfig中配置链接权限的时候,每次只要有一个新的链接,或则权限需要改动,都要在ShiroConfig.java中进行权限的修改。而且改动后还需要重新启动程序新的权限才会生效,很麻烦。解决办法就是将这些链接的权限存入数据库,在前端可以提供增删改查的功能,在配置文件中编写权限的时候从数据库读取,当权限发生变更的时候利用ShiroFilterFactoryBean的清空功能,先clear,再set。这样就可以做到到动态的管理权限了。
第二个问题:每次在访问设置了权限的页面时,都会去执行doGetAuthorizationInfo方法来判断当前用户是否具备访问权限,由于在实际情况中,权限是不会经常改变的。解决办法就是进行缓存处理。
此项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus
建立数据库
我们从ShiroConfig中的filterChainDefinitionMap.put("/add", "perms[权限添加]");
配置可以看出,我们需要存储链接,和链接需要具备的权限这两个关键字段。还有这个权限的读取是有顺序的,所以还要进行排序控制,所以我新建表为:
|
|
当然可以按实际情况进行表的设计,这里只做简单学习。
改造ShiroConfig.java
改造前:
|
|
改造后:
|
|
这里的selectAll()就是从数据库查询之前创建的权限管理列表,这里就不贴具体的查询代码了。
添加权限
在数据库中添加权限如下图:
现在启动程序,在控制台可以发现启动的时候程序在数据库查询了权限的列表信息。做到这步之后还没有达到动态的目的,比如现在到数据库手动修改/add链接的权限,这时不重启程序,权限是不会修改的。
动态更改权限实现
ShiroService.java:
|
|
这样,可以在修改权限之后,执行updatePermission()这个方法,权限就会先被clear,然后重新查询权限列表后再set。动态修改就实现了!
注意:在本学习项目里面,我在设置登录用户的权限的时候是写死了的,所以每个登录用户权限都是一样的,实际开发中在MyShiroRealm文件中设置登录用户的权限是从数据库获取的。还有在实际开发中sys_permission_init权限管理这种表是会在前端提供增删改查功能的,我学习的时候是直接在数据库手动修改。说到底,本人很懒!
我们知道Shiro 提供了一系列让我们自己实现的接口,包括org.apache.shiro.cache.CacheManager 、org.apache.shiro.cache.Cache 等接口。那么我们要对这些做实现,就实现了 Shiro 对 Session 和用户认证信息、用户缓存信息等的缓存,存储。我们可以用缓存,如 Redis 、 memcache 、 EHCache 等,甚至我们可以用数据库,如 Oracle 、 Mysql 等,都可以,只有效率的快慢问题,功能都可以达到。
那么我的教程是采用了 Redis ,而且是用了Jedis 。Jedis 可以实现pool 和hash 的集群Redis 。
本来我想是在网上学习学习,自己实现redis的集成。最后发现已经有大神已经做了这个插件,对shiro提供的CacheManager,Cache ,这些接口使用redis都有了很好的实现。我就不需要再费心学习了,我们就直接拿来用。
pom.xml依赖添加
|
|
改造ShiroConfig.java文件
|
|
这里,因为使用的是redis来做容器缓存,所以要创建redisManager来配置shiro,SessionManager(),cacheManager()这两个类都是插件给我们写好了的,里面就是对shiro提供的接口的redis实现方式。
使用插件就是这么简单,直接启动程序,多访问几次具有权限的页面,查看控制台发现,权限认证方法:MyShiroRealm.doGetAuthorizationInfo()会只执行了一次。说明我们的缓存生效了。
到此,我们集成shiro和redis,学习了一下功能的实现:
香蕉硬币点赞走一波啦。。。。。。
]]>用户必须要登陆之后才能访问定义链接,否则跳转到登录页面。
对链接进行权限控制,只有当当前登录用户有这个链接访问权限才可以访问,否则跳转到指定页面。
输入错误密码用户名或则用户被设置为静止登录,返回相应json串信息。
我是用的是之前搭建的一个springboot+mybatisplus+jsp的一个基础框架。在这之上进行shiro的整合。需要的同学可以去我的码云下载。
此项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus
|
|
RBAC 是基于角色的访问控制(Role-Based Access Control )在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。
|
|
Dao层的entity,service,mapper等我是采用mybatisplus的代码自动生成工具生成的,具备了单表的增删改查功能和分页功能,比较方便,这里我就不贴代码了。
ShiroConfig.java
|
|
在认证、授权内部实现机制中都有提到,最终处理都将交给Real进行处理。因为在Shiro中,最终是通过Realm来获取应用程序中的用户、角色及权限信息的。通常情况下,在Realm中会直接从我们的数据源中获取Shiro需要的验证信息。可以说,Realm是专用于安全框架的DAO.
Shiro的认证过程最终会交由Realm执行,这时会调用Realm的getAuthenticationInfo(token)方法。
该方法主要执行以下操作:1、检查提交的进行认证的令牌信息
2、根据令牌信息从数据源(通常为数据库)中获取用户信息
3、对用户信息进行匹配验证。
4、验证通过将返回一个封装了用户信息的AuthenticationInfo实例。
5、验证失败则抛出AuthenticationException异常信息。
而在我们的应用程序中要做的就是自定义一个Realm类,继承AuthorizingRealm抽象类,重载doGetAuthenticationInfo
(),重写获取用户信息的方法。
doGetAuthenticationInfo的重写
|
|
通俗的说,这个的重写就是我们第一个学习目标的实现。
shiro的权限授权是通过继承AuthorizingRealm抽象类,重载doGetAuthorizationInfo();
当访问到页面的时候,链接配置了相应的权限或者shiro标签才会执行此方法否则不会执行,所以如果只是简单的身份认证没有权限的控制的话,那么这个方法可以不进行实现,直接返回null即可。
在这个方法中主要是使用类:SimpleAuthorizationInfo
进行角色的添加和权限的添加。
authorizationInfo.addRole(role.getRole());
authorizationInfo.addStringPermission(p.getPermission());
当然也可以添加set集合:roles是从数据库查询的当前用户的角色,stringPermissions是从数据库查询的当前用户对应的权限
authorizationInfo.setRoles(roles);
authorizationInfo.setStringPermissions(stringPermissions);
就是说如果在shiro配置文件中添加了filterChainDefinitionMap.put(“/add”, “perms[权限添加]”);
就说明访问/add这个链接必须要有“权限添加”这个权限才可以访问,如果在shiro配置文件中添加了filterChainDefinitionMap.put(“/add”, “roles[100002],perms[权限添加]”);
就说明访问/add这个链接必须要有“权限添加”这个权限和具有“100002”这个角色才可以访问。
|
|
这个类的实现是完成了我们学习目标的第二个任务。
登录页面:
controller
|
|
jsp
|
|
controller
|
|
jsp
|
|
添加操作页面
controller
|
|
jsp
|
|
任务一
编写好后就可以启动程序,访问index页面,由于没有登录就会跳转到login页面。
登录之后就会跳转到index页面,点击退出登录后,有直接在浏览器中输入index页面访问,又会跳转到login页面
上面这些操作时候触发MyShiroRealm.doGetAuthenticationInfo()这个方法,也就是登录认证的方法。
任务二
登录之后访问add页面成功访问,在shiro配置文件中改变add的访问权限为
filterChainDefinitionMap.put(“/add”,”perms[权限删除]”);
再重新启动程序,登录后访问,会重定向到/403页面,由于没有编写403页面,报404错误。
上面这些操作,会触发权限认证方法:MyShiroRealm.doGetAuthorizationInfo(),每访问一次就会触发一次。
任务三
输入错误的用户名或则密码,返回“帐号或密码不正确!”的错误信息,在数据库中把一个用户的状态改为被禁用,再登陆,提示“帐号已经禁止登录!”的错误信息
上面的操作,是在MyShiroRealm.doGetAuthenticationInfo()登录认证的方法中实现的,通过查询数据库判断当前登录用户是否被禁用,具体可以去看源码。
当然shiro很强大,这仅仅是完成了登录认证和权限管理这两个功能,接下来我会继续学习和分享,说说接下来的学习路线吧:
shiro+redis集成,避免每次访问有权限的链接都会去执行MyShiroRealm.doGetAuthenticationInfo()方法来查询当前用户的权限,因为实际情况中权限是不会经常变得,这样就可以使用redis进行权限的缓存。
实现shiro链接权限的动态加载,之前要添加一个链接的权限,要在shiro的配置文件中添加filterChainDefinitionMap.put(“/add”, “roles[100002],perms[权限添加]”),这样很不方便管理,一种方法是将链接的权限使用数据库进行加载,另一种是通过init配置文件的方式读取。
Shiro 自定义权限校验Filter定义,及功能实现。
Shiro Ajax请求权限不满足,拦截后解决方案。这里有一个前提,我们知道Ajax不能做页面redirect和forward跳转,所以Ajax请求假如没登录,那么这个请求给用户的感觉就是没有任何反应,而用户又不知道用户已经退出了。
Shiro JSP标签使用。
Shiro 登录后跳转到最后一个访问的页面
在线显示,在线用户管理(踢出登录)。
登录注册密码加密传输。
集成验证码。
记住我的功能。关闭浏览器后还是登录状态。
还有没有想到的后面再说,欢迎大家提出一些建议。