哔哩哔哩:狂神说 Java
一、Shiro 简介?
Shiro 是一个 Java 的安全框架,不依赖任何容器,可以运行在 Java SE 和 Java EE 项目中,它的主要作用是对访问系统的用户进行身份认证,授权,会话管理,加密操作。
没有 Shiro 的时候,我们进行用户验证,可以使用过滤器,判断 session 是否存在
1.1 什么是权限
- 在 Web 系统中我们经常涉及到权限问题,例如不同角色的人登录系统,他操作的功能,按钮,菜单是各不相同的。这就是所谓的权限
1.2 权限校验
- 用户认证:用户身份识别,即登录
- 用户授权:访问控制
- 密码加密:加密敏感数据防止被偷窥
- 会话管理:与用户相关的时间敏感的状态信息
1.3 Shiro 的功能
- 可以在 Java SE 环境使用,也可以在 Java EE 环境使用
- 帮助我们完成:认证、授权、加密、会话管理、与web 集成、缓存
二、Shiro 核心组件及用户认证
2.1 Shiro 主要概念
用户,角色,权限
- 给角色赋予权限
给用户赋予角色
Subject: 就是与系统交互的当前“用户”,用户不仅仅是人,也可以是第三方服务,爬虫等正在与系统交互的任何事物
- SecurityManager:是 Shrio 框架的核心,协调内部各个安全组件之间的交互
- Realms:在 Shrio 和用户的应用程序之间扮演着桥梁和连接器的作用。当需要验证或者授权的时候,Shrio 从一个或者多个配置的 Realms 中查找
2.2 Shiro 核心 API
Shiro API | 功能 |
---|---|
UsernamePasswordToken | Shrio 用来封装用户的的登录信息,使用用户登录信息来创建令牌 |
SecurityManager | 相当于 SpringMVC 中的DispatcherServlet 或者 Struct2 中的 FiliterDispatcher;是 Shiro 的心脏;所有具体的交互都通过 SecurityManager 进行控制;它管理着所有的 Subject ;负责安全认证与授权、及会话、缓存的管理。 |
Subject | Shiro 的一个抽象概念,包含了用户信息。可以有一个或者多个 Realm,可以认为是安全试题数据源,既用于获取安全实体的;也可以是 JDBC 实现,也可以是 LDAP 实现,或者内存实现等等;由用户提供;注意 Shiro不知道你的用户/权限存储在哪以及何种格式存储;所以我们一般在应用中都需要实现自己的 Realm |
Realm | 开发者根据项目需求自定义的模块,验证和授权的逻辑全部写在Realm |
AuthenticationInfo | 用户角色信息集合。认证时使用 |
AuthorzationInfo | 角色权限信息集合,授权时使用 |
DefaultWebSecurityManager | 安全管理器开发者自定义的 Realm 需要到 DefaultWebSecurityManager,进行管理才能生效 |
ShiroFilterFactoryBean | 过滤器工厂,Shiro 的基本运行机制是开发者定义的规则,Shiro 去执行,具体的执行操作就是由 ShiroFilterFactoryBean 创建的一个个 Filter 对象创建完成 |
Authenticator | 认证器,负责主体认证的,这是一个扩展点,如果用户觉得 Shiro 默认的不好,可以自定义实现;其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了 |
Authorizer | 授权器:或者访问控制器,用来决定主体是否有权限进行相应的操作,即控制着用户能访问应用中哪些功能 |
2.3 用户认证流程
- 首先调用Subject.login(token)进行登录, 其会自动委托给Security Manager,调用之前必须通过SecurityUtis. setSecurityManager0设置;
- SecurityManager负责真正的身份验证逻辑: 它会委托给Authenticator进行身份验证;
- Authenticator才是真正的身份验证者,Shiro API中核心的身份认证入口点,此处可以自定义插入自己的实现;
- Authenticator可能会委托给相应的AuthenticationStrategy 进行多 Realm 身份验证,默认ModularRealmAuthenticator会调用 AuthenticationStrategy 进行多Realm身份验证;
- Authenticator会把相应的token传入Realm, 从Realm获取身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。
2.4 常见异常
2.5 用户认证常用方法
//获取当前用户
Subject currentUser = SecurityUtils.getSubject();
// 判断用户已经认证
currentUser.isAuthenticated()
// 用户登录
UsernamPasswordToken token = new UsernamePassword("admin","123312");
// 记住我
token.setRememberMe(true)
currentUser.login(token);
// 注解
@RequiresPermissions 要求当前 Subject 在执行被注解的方法时具备一个或多个对应的权限。
@RequiresRoles 要求当前 Subject 在执行被注解的方法时具备所有的角色,否则将抛出 AuthorizationException 异常
@RequiresAuthentication 要求在访问或调用被注解的类、实例、方法时,Subejct 在当前session 中已经被验证
三、用户授权流程
3.1 概念
授权(Authorization)也叫做访问控制,是一个对资源的访问进行管理的过程,也就是说在应用程序汇总,谁有怎样的权限(用户可以看到什么内容,可以进行什么操作)。在授权中需要了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)
四、自定义 Realm
五、过滤器集
四、SpringBoot 整合 Shiro
4.1 环境搭建以及测试
创建 SpringBoot 应用,集成 Shiro 坐标依赖,和其他相关依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- SpringBoot 整合 Shiro --> <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.10</version> </dependency> <!-- 使用 mybatis plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
测试项目环境是否完整
进入命令行,输入 mvn clean install 命令,当看到 build success 的时候,说明项目搭建完毕
- 自定义 Shiro 过滤器
3.2 Shiro 相关配置类编写
- 编写Realm,使用 Shiro 完成账号密码的验证,并生成 token ```java package com.gorit.realm;
import com.gorit.entity.Account; import com.gorit.service.AccountService; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired;
/**
- Shiro 自定义 realm
登录操作,过来权限的判断 */ public class AccountRealm extends AuthorizingRealm {
@Autowired private AccountService accountService;
/**
- 用户权限信息集合,授权时使用 *
- @param principalCollection
@return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; }
/**
- 用户角色信息,认证时使用
- 过程:
- 客户端传送过来的账号 和 密码,会封装到 token 里面
- 然后验证账户是否存在
- 账户存在就返回 SimpleAuthenticationInfo 对象 在判断传过来的密码和 token 里面的是否一致
- @param authenticationToken
- @return
- @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 获得 token
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
// token.getUsername()
Account account = accountService.findByUsername(token.getUsername());
// 验证账号是否存在
if (account!=null) {
} return null; } } ```// 密码验证 return new SimpleAuthenticationInfo(account,account.getPassword(),getName());
- 编写 Shiro 相关配置类 ```java package com.gorit.config;
import com.gorit.realm.AccountRealm; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
/**
- Shiro 的相关配置写在这里,权限认证做好了,就要编写配置
- realm 注入到 manager
- manager 注入到 */
@Configuration public class ShiroConfig {
// 创建一个对象,并丢入到 SpringIoc 容器中
@Bean
public AccountRealm accountRealm() {
return new AccountRealm();
}
// 安全管理器配置
@Bean
public DefaultWebSecurityManager securityManager(@Qualifier("accountRealm") AccountRealm accountRealm) {
// 创建对象
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
// 将注入到 IOC 的 Realm 取出来
manager.setRealm(accountRealm);
return manager;
}
// 配置过滤器工厂
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);
return factoryBean;
}
}
```
3.3 Shiro 编写认证和授权规则
认证过滤器
- anon:无需认证
- authc:必须认证
- authcBase:需要通过 HTTPBasic 认证
- user:不一定通过认证,只要曾经被 Shiro 记录即可,比如记住我
授权过滤器
- perms:必须拥有某个权限才能访问
- role:必须拥有某个角色才能访问
- port:请求的端口必须是指定值才可以
- rest:请求必须基于 RESTful POST GET DELETE PUT
- ssl:必须是安全的 URL 请求,协议 https
创建三个页面:main.html、manage.html、administrator.html
- 必须登录才能访问 main.html
- 当前用户必须拥有 manage 授权才能访问 manage.html
- 当前用户必须用用 administrator 角色才能访问 administrator.html