渐进式 shiro - shiro + jwt+salt (一)
admin
2024-01-28 21:29:33
0

本文简述:shiro基本使用

shiro 最常用得就是用来 处理登录接口 以及 处理其他需要在请求头中携带token的接口 这么一个框架。

Shiro 架构设计:

  • Authentication: 认证。如用户的登录。
  • Authorization: 授权。用户是否有权限访问指定 URL 等。
  • Cryptography: 密码学。如密码的加密。
  • Session Management: Session 管理。
  • Web Integration: Web 集成。Shiro 不依赖于容器。

shiro 登录认证流程:

  1. 用户访问登录接口 /login, 输入登录账号和密码被封装成 UsernamePasswordToken 对象.
  2. 接下来,登录服务中调用 subject.login() 方法,Shiro 立即进入用户认证过程,此认证过程做的事情式: 检验用户账号和密码是否正确

例子:使用 shiro.ini 固定配置文件

上面我们简述了 shiro 的结构以及最最简单得认证流程,你可能不太理解,不过没有关系,举个例子说明。

想一下我们最最简单的登录流程是怎么样的?用户输入用 户名和密码,然后访问登录接口,我们在 "/login"接口中接收到数据后,与数据库中的用户进行查找比较,返回该用户是否输入了正确的账号和密码。

我们先创建一个简单的示例来说明:

org.apache.shiroshiro-core1.10.0

创建一个用户信息文件: src/main/resources/shiro.ini ,此文件可以理解为 数据库

# ---------------------
# users用来定义用户
[users]
# 用户名 = 密码,角色1,角色2...
admin = 123456, admin
guest = guest, guest
aa = 123456, guest
# ---------------------
# roles用来定义角色
[roles]
# 角色 = 权限 (* 代表所有权限)
admin = *
# 角色 = 权限 (* 代表所有权限)
guest = select
aa = update

登录

@SpringBootTest
class ShiroTest {@Testpublic void testShiroAuth(){// 1.创建安全管理器DefaultSecurityManager securityManager = new DefaultSecurityManager();// 2.设置 realmsecurityManager.setRealm(new IniRealm("classpath:shiro.ini"));// 3.设置安全管理器SecurityUtils.setSecurityManager(securityManager);// 4.获取当前主体对象Subject subject = SecurityUtils.getSubject();// 5.将用户登录时的账号和密码封账成 UsernamePasswordToken 对象.// 此处写入 "admin", "password",表示用户输入的账号,密码UsernamePasswordToken token = new UsernamePasswordToken("admin", "password");try {System.out.println("登录认证前状态:" + subject.isAuthenticated());subject.login(token);System.out.println("登录认证后状态:" + subject.isAuthenticated());boolean permitted = subject.isPermitted("update");System.out.println(permitted);} catch (UnknownAccountException e) {System.out.println("用户不存在");} catch (IncorrectCredentialsException e) {System.out.println("账号或密码不正确");}}
}

shiro内部提供了两种方法创建 Realm 对象,这个小栗子中我们通过shiro提供得类IniRealm来读取文件 shiro.ini中写死得数据:

  1. 通过配置文件创建 Realm 对象: IniRealm 内封装了通过配置文件读取用户信息得方法,将此实例交给 SecurityManager 管理.
  2. 通过 springboot 中注解方式创建 Realm 对象: 实现接口 AuthorizingRealm,并在其 doGetAuthenticationInfo 方法中对登录信息进行校验处理 ,最终注入为 Bean

springboot 中使用 shiro

上面的代码,我们在一个测试方法中模拟了 shiro 的整个认证流程。
但是如果要在 springboot 中集成 shiro,可没有这么简单,我们需要将上面的 1,2,3,4,5 步骤分别拆开在不同的文件中,以达到更好的解耦性以及可扩展性,其实就是按照 java 的标准来。

因此我们首先需要了解一点 shiro 配置相关的东西。

shiro 的配置类主要包含三个 bean:

  • SecurityManager:安全管理器
  • shiroFilter:过滤器
  • Realm:realm 认证流程
  1. shiro 作为一个用来管理 http 请求框架,里面有非常多细节的功能,哪些功能启用,哪些功能不启用,是由控制中枢决定: SecurityManager
  2. shiro 集成到一个 springboot 项目中,而项目有许许多多的接口,哪些接口无需登录可以直接访问,哪些接口必须登录后带着 token 访问,这是由过滤器决定: shiroFilter
  3. shiro 作为一个通用的认证授权框架,并非只能在 springboot 中使用,因此框架专门将认证流程抽象后独立出来,产生了一个新的的概念:Realm.

到这里,shiro 中的三个核心概念你应该有所了解了,剩下的内容就式关于如何使用shiro: 在 springboot 中如何集成 shiro?

springboot 集成 shiro

在 springboot 中集成 shiro,还得再赘述几句。

spring 是用来管理 javaBean 对象的容器,集成 shiro 时,shiro 也同样要将上面提到的几个核心对象交给 spring 去管理。

先添加依赖

org.apache.shiroshiro-spring-boot-web-starter1.10.0

首先是配置,shiro 的三大核心,通过 @Bean 注册为spring中的bean对象交给 spring 去管理

@Configuration
public class ShiroConfig {/*** `SecurityManager`:安全管理器*/@Beanpublic DefaultWebSecurityManager getDefaultWebSecurityManager() {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(userRealm());return securityManager;}/*** `shiroFilter`:过滤器*/@Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager,ShiroFilterChainDefinition shiroFilterChainDefinition) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();// Shiro的核心安全接口,这个属性是必须的shiroFilterFactoryBean.setSecurityManager(securityManager);// 定义过滤链Map filterChainDefinitionMap = new LinkedHashMap<>();// 登录,不需要拦截的访问filterChainDefinitionMap.put("/login", "anon");// 其余所有接口都需要认证拦截filterChainDefinitionMap.put("/**","authc");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}/*** `Realm`:realm 认证流程*/@Beanpublic UserRealm userRealm() {return new UserRealm();}
}

在上面得演示代码中有报错,这是因为 UserRealm还不知道在哪里。回顾一下第一个的简单例子,我们是从shiro.ini这个文件中读取的用户数据,由shiro将文件中得数据封装成了Realm.

在实际项目中,我们需要从数据库中读取用户信息然后再比较,这个过程就需要我们自己来写。

如何做呢?实现AuthorizingRealm即可。

注意,userService 使用 mybatis 生成。

public class UserRealm extends AuthorizingRealm {@Autowiredprivate UserService userService;/*** 授权**/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}/*** 验证:用户登录* */@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {UsernamePasswordToken accessToken = (UsernamePasswordToken) authenticationToken;// 查询用户UserEntity user = Optional.ofNullable(userService.getOne(new LambdaQueryWrapper().eq(UserEntity::getUsername, accessToken.getUsername()))).orElseThrow(() -> new UnknownAccountException("账号或密码不正确"));//  验证密码SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(),getName());return authenticationInfo;}
}

我们实现 UserRealm 就是实现认证过程,里面有两个方法,单词十分的相近,并且登录认证使用下面那个 doGetAuthenticationInfo 方法.

  1. 在这一步中,doGetAuthenticationInfo 方法.有一个入参类型AuthenticationToken,它就是登陆时用户传入的账号和密码。没错,一旦我们重写之后,调用subject.login(),就会立即执行这一方法中的代码,你可以在此处打个断点感受一下。

  2. 我们将其向下转型,转换为 UsernamePasswordToken 这个类。UsernamePasswordTokenAuthenticationToken的一个实现类,比它多了若干的方法。

  3. 转换的目的是UsernamePasswordToken提供了一个获取用户名的方法,我们调用此方法拿到用户传过来的 username ,根据此 username 去查询数据库

  4. 接下来我们使用 shiro提供的类 SimpleAuthenticationInfo构造一个对象并返回。这里你一定会感到疑惑,怎么就直接返回了一个对象呢?正常来说,从数据库查到了用户密码后,应该进行比较啊,equal()呢,x == y 呢?

  5. shiro 为了将比较结果存储起来,将比较这一步骤也给封装起来了: 因此只要在方法中返回了 SimpleAuthenticationInfo这个类,接下来shiro就会在内部自动执行比较操作。

好的,接下来,你可以创建一个 controller,在数据库里创建一个用户,完整感受一下。

@RestController
public class UserController {@PostMapping("/login")public AjaxResult loginUser(@RequestBody UserEntity userVo) {Subject subject = SecurityUtils.getSubject();UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userVo.getUsername(), userVo.getPassword());usernamePasswordToken.setRememberMe(true);try {subject.login(usernamePasswordToken);System.out.println("登录成功");} catch (AuthenticationException ae) {System.out.println("登录失败: " + ae.getMessage());return AjaxResult.error("登录失败: " + ae.getMessage());}return AjaxResult.success(blogDto);}
}

相关内容

热门资讯

关于万历年间的一些民间故事? 关于万历年间的一些民间故事?万历年间的一天,广宁一个叫孙林的药材商在大街上闲逛,一个看相的一看到他,...
随身翻译机选择什么品牌好? 随身翻译机选择什么品牌好?1、随身翻译机怎么选购?2、随身翻译机随身翻译机到哪里买?3、随身翻译机里...
求“困知勉行”的解释 求“困知勉行”的解释kùn zhī miǎn xíng困知:遇困而求知;勉行:尽力实行。在不断克服困...
我该怎么整容了? 我该怎么整容了?我觉得你不用整容,你长得挺好的,男人结结实实就行,皮肤不太好,有豆豆,不要吃辛辣食物...
为什么叫云时代 为什么叫云时代就是一切资源都在云上,云指终端
综合来说,空客和波音哪家公司的... 综合来说,空客和波音哪家公司的飞机更好?波音比空客更好些。根据规模比较波音排名64,空客排名105。...
哪个季节适合出去旅游? 哪个季节适合出去旅游?在各种季节游玩中,人们讲的最多的是春游。因为人最喜欢的是新生的物品,而春天是万...
股市,情绪指标什么意思 股市,情绪指标什么意思市场情绪指标,是反应市场情绪的一种技术指标,可以反应出市场的情绪是否过热,还是...
双重身份用什么数字表示? 双重身份用什么数字表示?有一种说法叫斜杠青年。俺都是用负数表示负数表示多数是用X表示吗,我猜的2吧,...
谁能介绍一些关于爱情的书籍? 谁能介绍一些关于爱情的书籍?外国的有文学价值的书有些难啃,亚洲岩井俊二的情书,一定要看书,不是电影,...
六岁的小女孩上幸福来敲门 六岁的小女孩上幸福来敲门六岁的小女孩上幸福来敲门节目的需要吧挺有意思的看到还是有小孩子上的
马和鹿是什么成语 马和鹿是什么成语指鹿为马zhǐ lù wéi mǎ[释义] 把鹿说成马。比喻故意颠倒黑白。[语出]...
有没有主角穿越成狐仙,玉藻前,... 有没有主角穿越成狐仙,玉藻前,金毛白面九尾狐的综漫小说,同人小说?小鸡漫画上有一个,名字应该是《狐妖...
2-8人去张家界五日四晚跟团游... 最近我带着几位朋友计划了一次张家界五日四晚的旅行,人数在2到8人之间。说实话,一开始还担心价格太高或...
螳螂电视剧剧情介绍 螳螂电视剧剧情介绍 1948年冬,我军准备渡江作战,解放南京。国民党政府准备将一批珍贵国宝转运到台湾...
重庆旅游五日游多少钱,重庆旅游... 在繁忙的都市生活中,我总是渴望能带着孩子逃离喧嚣,去一个充满新奇与乐趣的地方,享受一段难忘的亲子时光...
鎏金观景台倒映江心·长桥衔日绘... 南京鱼嘴湿地公园以其独特的地理位置和丰富的湿地生态,融合了自然观赏、生态保护教育、休闲娱乐与亲子活动...
平时出行意外险该选哪个?综合意... 平时出行意外险该选哪个?综合意外险有什么好处?平时出行一定要注意安全,保险的配备也是十分必要。一般来...
丽江文旅推介走进成都,邀您体验... 当苏超球迷嗨到冒烟,兵马俑人潮涌动,重庆火锅沸腾至凌晨3点,成都世运会即将燃爆全城之际,云南丽江市却...
直男眼里的《山河令》逗乐网友,... 直男眼里的《山河令》逗乐网友,直男眼里的这部剧是怎样的?在直男的眼中,这就是知己的感觉,这就是真的兄...