Shiro基本功能

Shiro架构
- 从外部来看shiro的架构

Application Code:应用代码
Subject:主体(用户,第三方等与程序对接的会话主体)
Security Manager 安全核心(Shrio 的核心功能)
realm:域,相当于数据源,通过realm存取认证、授权相关数据。(securityManager的授权和认证的逻辑最终都是交给在这里执行的,可以理解为调用数据库查询一系列的信息,然后用这些信息和login的参数进行匹配,一般情况下在项目中采用自定义的realm,因为不同的业务需求不一样)
- 内部框架

环境搭建
导入配置
<dependencies><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.9.0</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency></dependencies>
Shiro获取权限相关信息可以通过数据库获取,也可以通过ini配置文件获取
登录认证
首先说明登录认证的基本流程是
- 收集用户名和密码也就是用户的凭证
- 调用
Subject.login()进行登录 - 创建自定义的Realm类,继承
AuthorizingRealm类,实现doGetAuthenticationInfo()
示例:
package com.sftest.logintest;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.config.IniSecurityManagerFactory;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.subject.Subject;public class logintest {public static void main(String[] args) {//1. 初始化获取SecurityManagerIniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);//2. 获取Subject对象Subject subject = SecurityUtils.getSubject();//3. 创建token对象,web应用用户名密码从页面传递UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "z3");//4. 完成登录try {subject.login(token);System.out.println("登录成功");} catch (UnknownAccountException e) {e.printStackTrace();System.out.println("用户不存在");} catch (IncorrectCredentialsException e) {e.printStackTrace();System.out.println("密码错误");} catch (AuthenticationException e) {e.printStackTrace();}}}
问题解决:
F:Ctrl+Alt+V快捷键突然使用不了?
Q:查看是否是快捷键冲突占用,QQ音乐的快捷键冲突,关闭即可
F:报错java: JDK isn’t specified for module
Q:IDEA自带的JDK有问题,换成自己安装的JDK就可以了
示例结果

接下来对这段简单的登录验证逻辑进行Debug,查看具体代码实现。
在login处下个断点,调试走到这里,可以看到实际上调用的login方法是在DelegatingSubject类中的login方法
到这里看到username和password的值,然后看到实际上是securitymanager调用login方法

继续跟进,DefaultSecurityManager下的login方法,已经走到了authenticate()

走到AuthenticatingSecurityManager类下的authenticate方法,一个认证器(authenticator)调用了authenticate方法

还没看到方法实现的地方,继续跟进,最终在AbstractAuthenticator类中找到了token,发现又交给了另一个方法去处理了

真能藏,然后到这里它改名字了,叫authenticationToken,然后这里有个逻辑,同步也是发现这里用到了realm对象,调试到这一步的时候就已经发现size=1,所以这里调用的应该是doSingleRealmAuthentication方法

继续跟进,到了doSingleRealmAuthentication类中,又发现token传递到了一个方法里面

继续跟,到这里终于看到了有点逻辑了,看下它又做了什么
好像是获取这个token相关的缓存了,但是没有获取到,所以info为null,然后就继续看,发现处理token的方法是doGetAuthenticationInfo

而 Shiro的认证依赖AuthenticatingRealm里的getAuthenticationInfo方法,该方法会调用我们自定义的认证方法<font style="color:rgb(77, 77, 77);">doGetAuthenticationInfo</font>,获取本次认证的结果。

最终走完过程(没有走rememberme这个逻辑)

角色授权
授权:访问控制(访问页面,编辑数据,页面操作),在授权中用到的几个对象:Subject(主体),Resource(资源),Permission(权限),Role(角色)
- 角色授权的三种方式
- 代码式:通过
if{}else{}来进行控制 - 注解:使用注解,有权限则进一步调用,没权限抛出异常
@RequiresRoles - 标签:Shiro自带标签
<shiro:hasRole name="admin"></shiro:hasRole>
设置角色需要在shiro.ini中进行配置
判断用户是否拥有角色权限:
//shiro.ini[users]zhangsan=z3, role1, role2//.javaboolean role1 = subject.hasRole("role1");
用户操作权限,在配置文件中进行设置
//shiro.ini[roles]role1=user:insert, user:select//.javaboolean permitted = subject.isPermitted("user:insert");
还有一个方法来检查权限
subject.checkPermission("user:select");
没有返回值,有权限直接向下执行,没有权限抛出异常。

Shiro加密
- Md5加密测试
为保障安全,还可以进行md5多次迭代加密。
package com.sftest.logintest;import org.apache.shiro.crypto.hash.Md5Hash;public class CryptoTest {public static void main(String[] args) {//MD5加密测试String password = "m0rewuwuwuwu";Md5Hash md5Hash = new Md5Hash(password);System.out.println(md5Hash.toHex());//加盐Md5Hash woc = new Md5Hash(password, "woc");System.out.println(woc.toHex());//多次迭代加盐Md5Hash hash = new Md5Hash(password, "woc", 3);System.out.println(hash);//使用父类进行加密SimpleHash simpleHash = new SimpleHash("MD5","m0rewuwuwuwu","woc",3);System.out.println(simpleHash);}}
然后看了下MD5加密的源码,其实是

观察使用父类进行加密的代码,似乎明白了点什么。
