SHIRO的那些事儿
Shiro百度百科:
Apache Shiro
Apache Shiro(日语"堡垒(Castle)"的意思)是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理功能,可为任何应用提供安全保障 - 从命令行应用、移动应用到大型网络及企业应用。
Shiro为解决下列问题(我喜欢称它们为应用安全的四要素)提供了保护应用的API:
认证 - 用户身份识别,常被称为用户"登录";
授权 - 访问控制;
密码加密 - 保护或隐藏数据防止被偷窥;
会话管理 - 每用户相关的时间敏感的状态。
Shiro还支持一些辅助特性,如Web应用安全、单元测试和多线程,它们的存在强化了上面提到的四个要素。
主要功能如图:
核心功能:
Authentication:身份认证(登陆)
Authorization:权限控制,授权(permission)
SessionManagement: session管理
Cryptography: 加密
一、基础用法:
初始化一个安全管理工厂类,初始化的时候将shiro简单的用户密码配置读取进去(即textrealm,realm:域,shiro中用realm来配置用户信息,分jdbcrealm,textrealm,jndirealm),格式通常为:
[用户]
用户名=密码
然后通过工厂类来获取securityManager实例
再通过为SecurityUtils设置securityManager就可以通过该util获取subject
也就是当前的用户(这里的用户就是一开始读取到的shiro配置中的用户)
到这一步其实就是 shiro将用户的账号密码信息管理好了
当用户登陆的时候,就用了UsernamePasswordToken来配置登陆信息
然后通过用户的login方法来尝试登陆
Subject.login(token)这里如果登陆失败会抛出异常,捕获一下就好。
这里就实现了一个简单登陆。
二、使用jdbcRealm登陆
jdbcRealm是一个神奇的realm,配置xml如下:
目前用的是oracle,和c3p0连接池,先看一下shiro的jdbcRealm类中大概是什么样子的:
这时候我们已经配置了连接池,也就是说,其他的不变,我们直接运行刚刚的测试类,他就会去查users表,然后我们通过token来配置账号密码后就可以继续用login方法登陆,如果说用的是Mysql的话,肯定是没有问题的,但是!
这里划重点!!!!!!
可能我是比较笨,用了oracle这个库,肯定是有问题的,运行的时候肯定会一直报表或视图不存在!
真的是表不存在吗?查询后发现,表是存在的,但是sql肯定是有问题的,users在oracle中属于关键字(表),所以查不到,然后我为了区别于users表,又copy了一张一模一样的表,名字叫users1。
然后修改配置文件,添加jdbcRealm.authenticationQuery,这里的配置文件就像spring中的依赖注入一样,可以为属性注入值,修改该sql为从users1中查,还是会提示表或视图不存在,所以这里一定要记住,使用oracle的话,如果一定要用jdbcRealm而不是自己写realm的话,一定要修改配置中的sql ,并且避开users关键字,最好sql也规范性大写。
三、role(角色)、permission(权限)的简单使用
Xml配置中,加入role和permission就可以在测试类中使用hasRole和isPermission方法来判断是否有role和permission,也可以用check方法,但是check是用抛异常的形式来判断的,所以不推荐。
Xml如下:
测试类如下:
封装的ShiroUtil如下:
四、整合spring并实现shiro的身份认证、权限认证、加密等功能
Spring整合shiro需要用到spring依赖包及shiro依赖包和一些common包如下:
Spring相关配置不做赘述,主要是集成shiro的一些配置:
现在web.xml中添加shiro的监听:
该监听是将shiro托管给spring,可见该监听是在spring包下的。
初始化参数targetFilterLIfecycle默认是false,该配置是shiro的filter生命周期配置,默认是shiro自己管理,当设置为true的时候,就交由spring来管理,这个操作我猜想应该是统一生命周期,方便容器的操作。
然后在spring的配置文件中,加入shiro的securityManager bean
Spring的配置中关于shiro的配置可参考官方文档:
http://shiro.apache.org/spring
但是官方文档中有一些地方要注意:
这里的securityManager和
这里的securityManager是有差别的!!!!!
目前我也不知道为什么官方文档要那么写,按官方文档的第一个配置来写,然后我看到applicationContext.xml中的配置 有相同bean,默认我就跳过没有添加,最后在启动的时候一直在报过滤器错:
提示没有实现WebsecurityManager接口
这个问题还是比较罕见,可能遇到的人不多..这里shiro官方文档中的第一个securityManager和第二个bean的实现指向了不同的类。
这步做对以后,基本配置如图:
AuthorizationAttributeSourceAdvisor这个bean是在spring中注册shiro的注解支持。
在前面的配置文件中,写了用户信息,权限信息和permission认证信息,在这里都已经入库存放,shiro在login的时候会去匹配securityManager中的realms ,也就是配置文件信息。入库以后我们可以使用jdbcRealms,也可以自己实现realm,这里我是自己实现了realm,代码如下:
自定义realm继承AuthorizingRealm,最最底层的接口是Realm接口,有兴趣可以研究源码。
里面主要是要重写两个父类方法:
AuthorizationInfo:授权
AuthenticationInfo:身份认证。
在applicaitionContext.xml中我们还配置了对具体的请求做权限控制,如果一个请求配置为anon的话,则不会调用realm,而是直接执行该请求,顺序是:请求->filterChainDefinitions->如果anon则直接执行,如果authc,则需要身份认证,这里就会进入loginUrl,在loginUrl的controller中会进行登陆然后进入realm进行身份认证,如果authc后面追加有权限认证,则会执行realm中的权限认证。都通过的时候进入successUrl。
此后的每一个请求都按这个顺序执行,如果登陆成功,但是权限不足,则会跳转到unauthorizedUrl中。
Logout在applicationContext中也有配置,这里要注意的是,光配置bean是不够的,还要在ShiroFilterFactoryBean中将logout配置到filters里面,这里用了spring的util xmlns,然后在xml中就可以使用util:map的方法进行批量配置list。
关于加密:
Shiro提供了多种加密方案:base64 md2 md5 hex等
具体调用代码如下:
推荐使用md5加密,因为如果使用base64,加密方式比较简陋,有可能会通过一些暴力方式破解密码,比如撞库等,但是md5就相对来说更加安全一些,可以先用自己的一种编码生成一个salt(盐),然后再通过改salt生成一个不可逆的md5,这种方式会安全很多。
使用加密的时候,就是在注册用户的时候将用户密码跟随生成的盐直接加密之后入库,在验证登陆的时候,用加密方法+盐来加密后进行身份认证。
关于remember me:
Shiro还提供一些小功能比如用户的"记住我"功能,当用户勾选记住我的时候,在后台对token进行setRememberMe(true),就可以在默认时间范围内记住该用户的登陆状态。