一、Shiro框架概念
(一)Shiro框架概念
1.概念:
- Shiro是apache旗下一个开源安全框架,它对软件系统中的安全认证相关功能进行了封装,实现了用户身份认证,权限授权、加密、会话管理等功能,组成一个通用的安全认证框架。
- 工作流程如下图所示:
2.Shiro框架的三大组件:
- Subject:主体对象,用于提交用户认证和授权作息。
- SecurityManager:安全管理器,负责认证、授权等业务实现。(程序员需要配置该类)
- Realm:领域对象,负责从数据层获取业务数据。(需要程序员提供Shiro框架定义的抽象类AuthorizingRealm(授权Realm)或AuthenticatingRealm(认证Realm)。
- 三大组件工作流程
3.Shiro框架的相关组件具体作用:
- Shiro框架进行权限管理时,涉及了一些核心对象,主要包括:认证管理对象,授权管理对象,会话管理对象,缓存管理对象,加密管理对象以及Realm管理对象等。
- 具体架构如图所示:
- 核心对象具体作用:
- Subject:与软件交互的一个特定的实体(用户、第三方服务等)。
- SecurityManager:Shiro的核心,用来协调管理组件工作。
- Authenticator:负责认证操作。
- Authorizer:负责授权检测。
- SessionManager(会话管理):负责创建并管理用户Session生命周期。
- SessionDao:代表SessionManager执行Session持久(CRUD)操作,它允许任何存储的数据挂接到Session管理基础上。
- CacheManager:提供创建缓存实例和管理缓存生命周期的功能。
- Cryptography(加密管理器):提供了加密方式的设计及管理。
- Realm(领域对象):是Shiro和应用程序安全数据的桥梁。
二、SpringBoot整合Shiro
(一)所需依赖
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-web-starter</artifactId><version>1.7.1</version> </dependency>
1.当添加该依赖后需要对项目进行初始化否则项目会启动失败。
原因:添加该依赖启动项目时,Shiro框架会要求创建一个Realm对象并交给Spring框架管理。
(二)完成Shiro配置
1.在application.yml/application.properties文件中
shiro:loginUrl: /login
(三)完成Shiro框架整合
- 提供Realm的实现类:
- Realm定义与实现结构及提供Realm实现类的方式
- 具体实现过程:
- 提供Realm的具体实现类SysShiroRealm.
- 将SysShiroRealm对象交给Spring管理。如下图:
三、通过Shiro框架认证实现
(一)配置认证过滤链
1.实现方法:
- 配置一个ShiroFilterChainDefinition的实现类DefaultShiroFilterChainDefinition对象,在该对象中配置具体过滤链。完成配置后将该对象交于Spring管理。
2.具体实现:
@Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() {DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();chainDefinition.addPathDefinition("/login", "anon");chainDefinition.addPathDefinition("/assets/**", "anon");chainDefinition.addPathDefinition("/forgetpw", "anon");chainDefinition.addPathDefinition("/user/logininfo", "anon");chainDefinition.addPathDefinition("/logout", "logout");/*chainDefinition.addPathDefinition("/**", "authc");*/return chainDefinition; }
- 细节如下图所示
(二)提交用户登录信息给Shiro框架的securityMananger。
实现方法:通过Subject对象调用login()方法实现。
第一步:从前端获取用户信息通过Ajax或Axios提交给controller。
第二步:controller获取前端提供的用户登录信息,并封装成UsernamePasswordToken做为参数传递给Subject对象。Subject对象调用login方法将用户登录信息提交给SecurityManager进行登录校验。具体如下图:
(三)数据库获取用户认证信息交给Shiro框架的SecurityManager。
实现方法:通过重写doGetAuthenricatingInfo()实现
第一步:向SecurtiyManager提供用户凭证加密方式:
- 原因:
- 由于通过Subject的login方法传给SecurityManager的用户的密码为明文密码,而数据库中保存的是加密盐和加密密码,因此需要提供加密方法,供SecurityManager调用对明文密码进行加密操作完成与加密后的密码校验。
- 方法:
- 提供加密方法需要重写AuthorizingReaml的方法getCredentialsMatcher方法,该方法返回一个CredentialsMatcher(凭证匹配器)的实现类HashedCredentialsMatcher(针对MD5加密)的对象。
- 具体实现:
第二步:重写认证方法doGetAuthenticatingInfo方法,返回一个AuthenticationInfo的实现类SimpleAuthenticationInfo对象。用于封装数据库中用户凭证信息。
- 目的:封装从数据库获取的用户凭证信息,用于SecurityManager认证操作。
- 具体实现:
-
-
- 其中:SimpleAuthenticationInfo对象的构造方法:如图所示。
-
(四)完成认证
- 由SecurityManager内部完成,无需程序员干预。
(五)对认证结果进行处理。
1.SecurityMananger认证结果:
- 用户不存在:SecurityManager抛出UnknowAccountException。
- 密码不匹配:SecurityManager抛出IncorrectCredetialsException。
- 账号锁定:SecurityManager抛出LockedAccountException。
2.通过全局异常处理类完成认证结果信息普通化:
(六)获取用户登陆信息
1.方法:
- 通过shiro框架的subject组件获取。
2.具体实现:
-
SysUsersPojo usersPojo = (SysUsersPojo) SecurityUtils.getSubject().getPrincipal();
四、通过Shiro框架实现授权
(一)实现授权的方式
- Shiro框架实现授权是通过AOP的方式实现的。
- 底层通过@annontation切入点表达式来定义切点。
- 自定义的Annontation为@RequiresPremissions。
- 注解实参:自定义的授权标识标识。
- 作用:用于标识访问该方法需要的权限。
- 目标方法是需要授权才能访问的方法。
- 具体使用方法:
- 底层通过@annontation切入点表达式来定义切点。
(二)授权的前置依赖
- 由于Shiro框架的授权是通过AOP来实现的,因此,要实现Shiro授权,就必须在项目中添加SpringAop依赖。
- 即:
-
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId> </dependency>
-
(三)授权实现流程
1.认证是授权的基础。
2.实现流程
- 当用户访问需要授权的资源时,SecurityManager调用Realm中的doGetAuthorizationInfo()方法。
- 该方法从用户认证信息中获取用户信息。
- 通过用户信息获取用户所拥有的所有授权信息,封装成AuthorizationInfo实现类的对象。
- SecurityManager内部完成授权信息校验。
- 如果用户拥有该授权标识,则访问该方法;如果用户没有该授权标识,则SecurityManager出抛出AuthorizationEexception,终止访问。
(四)具体实现过程
1.使用@RequiresPermissions描述需要授权才能访问的方法。
2.重写Realm中的doGetAuthorizationInfo方法,用于封装数据库的保存的该用户拥有的所有授权标识以供SecurityManager授权校验时使用。
3.授权中可能存在的问题
- 存在问题:当使用@RequiresPermissions注解描述需要授权访问的Controller层方法时,导致该方法无法被访问。
- 产生原因:
- Shiro框架实现授权是通过AOP的方式实现。
- 当@RequiresPermissions描述目标方法时,Shiro会为该方法所在类创建一个CGLIB代理对象。
- 在创建代理对象时,默认情况下,原Controller方法上的@RequestMapping等类似注解失效。导致无法访问该Controller方法。
- 解决方法:
- 解决原理:
- AOP创建代理对象是通过DefaultAdvisorAutoProxyCreator对象完成的。
- 解决方法:
- 修改DefaultAdvisorAutoProxyCreator对象配置,让原对象上注解生效。
- 具体实现。
- 解决原理:
五、认证授权总结
(一)用户信息流转流程
- 提供Realm的具体实现类SysShiroRealm.