作者 : Stanley 罗昊
* 观看本文章需要有一定 SpringBoot 整合经验 *
Shiro 框架简介
Apache Shiro 是一个强大且易用的 Java 安全框架, 执行身份验证, 授权, 密码学和会话管理. 使用 Shiro 的易于理解的 API, 可以快速, 轻松地获得任何应用程序,
从最小的移动应用程序到最大的网络和企业应用程序.
分析 Shiro 的核心 API
其实, Shiro 的核心类有三个, 分别是:
1.Subject: 这个类呢, 我们称之当前用户的主体, 这个用户的主体包含了登陆, 注销等等的一些方法, 还有一些判断授权的一些方法;
2.SecurityManager: 这个名称翻译过来就是, 安全管理器的意思;
3.Realm: 这个 Realm 呢其实我们 Shiro 去链接数据库的一个桥梁, 因为, 我们的程序需要去操作数据库去获取一些用户的信息, 这些操作都需要 Realm 去完成;
这个三个 API 呢, 都存在一些关系, 比如. SecurityManager 是需要去关联我们的 Realm,Subject 是需要把操作交给我们的 SecurityManager, 总结下来就是, Subject 是需要去管理我们的 SecurityManager, 而 SecurityManager 去关联我们的 Realm;
以上就是对 Shiro 的核心 API 进行的一些分析;
分析完之后, 我们接下来就直接用 SpringBoot 与 Shiro 的整合, 我们来看下它整合的关键步骤
SpringBoot 整合 Shiro
那么这个整合首先第一步需要导入 Shiro 的依赖;
[因为我用的是 Gradle, 所以仅展示 Gradle 用法]
1. 修改. gradle 文件, 添加以下依赖
- //Thymeleaf 模板引擎, 因为我用模板引擎所以我添加了此依赖
- compile group: 'org.thymeleaf', name: 'thymeleaf', version: '3.0.11.RELEASE'
- //Shiro
- compile group: 'org.apache.shiro', name: 'shiro-web', version: '1.4.0'
- compile group: 'org.apache.shiro', name: 'shiro-core', version: '1.4.0'
- // https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring
- compile group: 'org.apache.shiro', name: 'shiro-spring', version: '1.4.0'
2. 编写 Shiro 的配置类
配置类需要三样 API, 分别是:
- /**
- * 创建 ShiroFilterFactoryBean
- * shiro 过滤 bean
- */
- /**
- * 创建 DefaultWebSecurityManager
- */
- /**
- * 创建 Realm
- */
如图:
3. 自定义 Realm 类
因为我们需要在配置类中创建出 Realm 对象, 所以我们需要建一个名为 Realm 的类:
创建后, 需要继承一个方法, 这个方法是 Shiro 提供的:
- /**
- * 自定义 Realm
- */
- public class UserRealm extends AuthorizingRealm {
- // 执行授权逻辑
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- return null;
- }
- // 执行认证逻辑
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
- return null;
- }
4. 在配置类中 new 出 Realm
Shiro 配置配置类
- package com.lh.shiroStudy.shiro;
- import org.apache.shiro.spring.Web.ShiroFilterFactoryBean;
- import org.apache.shiro.Web.mgt.DefaultWebSecurityManager;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import java.util.LinkedHashMap;
- import java.util.Map;
- /**
- * Shiro 配置类
- */
- //@Configuration, 声明本类是一个配置类
- @Configuration
- public class ShiroConfig {
- /**
- * 创建 ShiroFilterFactoryBean
- * shiro 过滤 bean
- */
- @Bean
- public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
- ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
- // 设置安全管理器
- shiroFilterFactoryBean.setSecurityManager(securityManager);
- // 添加 Shiro 过滤器
- /**
- * Shiro 内置过滤器, 可以实现权限相关的拦截器
- * 常用的过滤器:
- * anon: 无需认证 (登录) 可以访问
- * authc: 必须认证才可以访问
- * user: 如果使用 rememberMe 功能可以直接访问
- * perms: 该资源必须得到资源权限才可以访问
- * role: 该资源必须得到角色权限才可以访问
- */
- Map<String,String>filterMap = new LinkedHashMap<String, String>();
- // 左边编写拦截路径
- filterMap.put("/add","authc");
- filterMap.put("/update","authc");
- filterMap.put("/testThymeleaf","authc");
- // 授权过滤器
- // 注意: 当前授权拦截后, shiro 会自动跳转未授权页面
- filterMap.put("/add","perms[user:add]");
- // 修改跳转的登陆页面
- shiroFilterFactoryBean.setLoginUrl("/toLogin");
- // 转跳至未授权页面[友好提示]
- shiroFilterFactoryBean.setUnauthorizedUrl("/aaaaaa");// 懒省事所以没有 aaaa 这个页面, 如果需要, 请在 Contoller 中添加
- shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
- return shiroFilterFactoryBean;
- }
- /**
- * 创建 DefaultWebSecurityManager
- */
- @Bean(name = "securityManager")
- public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("UserRealm") UserRealm userRealm){
- DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
- securityManager.setRealm(userRealm);
- return securityManager;
- }
- /**
- * 创建 Realm
- */
- @Bean(name = "UserRealm")
- public UserRealm getRealm(){
- return new UserRealm();
- }
- }
Realm 类
- package com.lh.shiroStudy.shiro;
- import org.apache.shiro.authc.*;
- import org.apache.shiro.authz.AuthorizationInfo;
- import org.apache.shiro.authz.SimpleAuthorizationInfo;
- import org.apache.shiro.realm.AuthorizingRealm;
- import org.apache.shiro.subject.PrincipalCollection;
- /**
- * 自定义 Realm
- */
- public class UserRealm extends AuthorizingRealm {
- // 执行授权逻辑
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- // 给资源进行授权
- SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
- // 添加资源的授权字符串
- //info.addStringPermission("user:add");
- // 到数据库查询当前登陆用户的授权字符串
- /**
- * <!- 演示状态 -!>
- * 获取当前用户
- * Subject subject = SecurityUtils.getSubject();
- * User user = (User)subject.getPrincipal();
- * User dbUser = userService.findById(id)
- * info.addStringPermission(dbUser.getPerms());
- * </!- 演示状态 -!>
- */
- System.out.println("执行授权逻辑");
- return null;
- }
- // 执行认证逻辑
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
- System.out.println("执行认证逻辑");
- // 假设数据库账号与密码是如下
- String username = "admin";
- String password = "123456";
- /**
- * 编写 Shiro 判断逻辑, 比对用户名和密码
- */
- //1. 判断用户名
- UsernamePasswordToken token =(UsernamePasswordToken)arg0;
- //User user = userService.findByName(token.getUsername());
- if (user == null){
- // 用户名不存在
- return null;// 如果返回 null,Shiro 底层会抛出 UnknowAccountException
- }
- //2. 判断密码
- /**
- * 有三个参数
- * 1. 需要返回给 login
- * 2. 是数据库的密码, 将数据库密码返回, Shiro 会自动判断
- * 3. 是 Shiro 的名字
- */
- return new SimpleAuthenticationInfo(user,password,"");
- }
- }
来源: https://www.cnblogs.com/StanleyBlogs/p/11407350.html