IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringBoot整合shiro -> 正文阅读

[Java知识库]SpringBoot整合shiro

shiro介绍

官网: Apache Shiro | Simple. Java. Security.

Shiro 是 Java 的一个安全(权限)框架。

shiro功能

Shiro 可以完成:认证、授权、加密、会话管理、与Web 集成、缓存等。

  • Authentication: 身份认证/登录,验证用户是不是拥有相应的身份

  • Authorization: 授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能进行什么操作,如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限

????????...... (其他功能略,自己百度)

shiro核心组件

下述为实现shiro较为核心的几个组件

?ShiroFilterFactory是整个Shiro的入口点

简而言之:?

  • 对于Realms,我们只需要继承 抽象类 AuthorizingRealm 即可发现,我们需要重写两个方法,分别是用于实现认证功能的 doGetAuthenticationInfo方法 和用于实现授权的doGetAuthorizationInfo方法。

  • SecurityManager属于一个中间安全管理器,通过它可实现各种安全服务

  • ShiroFilterFactoryBean则属于一个过滤器工厂,我们可以在这里定义哪些接口需要认证和授权

而对于shiro的快速入门,其实就是对以上的,SecurityManager、Realms、ShiroFilterFactoryBean三个类的重写与实现。

使用

????????我这个只演示认证功能的实现,其他功能,如授权。可以询问学长们,或者自行百度。

????????创建一个普通的SpringBoot工程,只需要选择web依赖即可。

1、引入依赖

?<!--shiro-->
?<dependency>
? ? ?<groupId>org.apache.shiro</groupId>
? ? ?<artifactId>shiro-spring-boot-web-starter</artifactId>
? ? ?<version>1.4.0</version>
?</dependency>
?<!--lombok-->
?<dependency>
? ? ?<groupId>org.projectlombok</groupId>
? ? ?<artifactId>lombok</artifactId>
?</dependency>

2、编写用于测试的基本接口

????????VO类,用于接收用户名和密码

?@Data
?public class UserLoginVo {
? ? ?private String userName;
? ? ?private String passWord;
?}

????????登录接口和另一个普通访问的接口

?@RestController
?public class UserController {
? ? ?
? ? ?/**
? ? ? * 登录
? ? ? *
? ? ? * @param loginVo 用户名和密码
? ? ? * @return {@link String}
? ? ? */
? ? ?@PostMapping("/login")
? ? ?public String login(@RequestBody UserLoginVo loginVo) {
?        System.out.println(loginVo);
? ? ? ? ?return "登录成功";
? ?  }
??
? ? ?@GetMapping("/hello")
? ? ?public String hello() {
? ? ? ? ?System.out.println("hello");
? ? ? ? ?return "打招呼";
? ?  }
??
?}

????????用接口测试两个接口,都可使用

3、实现shiro核心组件

Realms组件的实现

?@Component
?public class AccountRealm extends AuthorizingRealm {
??
? ? ?// 授权
? ? ?@Override
? ? ?protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
? ? ? ? ?System.out.println("授权");
? ? ? ? ?return null;
? ?  }
??
? ? ?// 认证
? ? ?@Override
? ? ?protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
? ? ? ? ?System.out.println("认证");
? ? ? ? ?// 获取登录的用户名
? ? ? ? ?String username = (String) token.getPrincipal();
? ? ? ? ?// 判断改用户是否存在
? ? ? ? ?if (!"hsx".equals(username)) {
? ? ? ? ? ? ?throw new UnknownAccountException("账户不存在!");
? ? ? ?  }
? ? ? ? ?// 验证密码
? ? ? ? ?return new SimpleAuthenticationInfo(username, "123", getName());
? ?  }
?}

????????在此处,我账号和密码分别写死为 "hsx" 和 "123"。在实际开发中,这部分的账号和密码的验证,应该是来着查询数据库的。?

ShiroFilterFactoryBean和SecurityManager组件的实现

????????在这里,我直接演示使用注解的方法来实现安全管理。

?@Configuration
?public class ShiroConfig {
? ? ?//DefaultWebSecurityManager 安全管理器
? ? ?@Bean
? ? ?public DefaultWebSecurityManager securityManager(AccountRealm accountRealm) {
? ? ? ? ?DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
? ? ? ? ?//关联 我们自定义的AccountRealm
? ? ? ? ?securityManager.setRealm(accountRealm);
? ? ? ? ?return securityManager;
? ?  }
??
? ? ?//shiroFilterFactoryBean
? ? ?@Bean
? ? ?public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
? ? ? ? ?ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
? ? ? ? ?//设置安全管理器
? ? ? ? ?bean.setSecurityManager(securityManager);
? ? ? ? ?return bean;
? ?  }
? ? ?
? ? ?//开启注解代理(默认好像已经开启,可以不要)
? ? ?@Bean
? ? ?public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
? ? ? ? ?AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
? ? ? ? ?authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
? ? ? ? ?return authorizationAttributeSourceAdvisor;
? ?  }
??
? ? ?@Bean
? ? ?public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
? ? ? ? ?DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
? ? ? ? ?creator.setProxyTargetClass(true);
? ? ? ? ?return creator;
? ?  } ? ?
? ? ?
?}

4、测试

????????在配置了shiro的三个核心组件,SecurityManager、Realms、ShiroFilterFactoryBean。而且,重写了Realms中的认证方法。那我们就可以按照我们定义的规则进行认证了。

????????只要我们在Controller接口上加上@RequiresAuthentication注解,那么该接口就需要认证之后才能访问。

?@GetMapping("/hello")
?@RequiresAuthentication
?public String hello() {
? ? ?System.out.println("hello");
? ? ?return "打招呼";
?}

????????重启服务,调用 'hello' 接口。然后发现,系统报错,提示我们权限不足。无法访问该接口。

????????若要访问改接口,那么我们需要进行认证

????????在shiro中,只有调用SecurityUtils.getSubject()中的login,才可反问我们上面定义的doGetAuthenticationInfo方法。?

????????所以,我们在login接口调用我们上述所说的方法,将前端传过来的账号和密码都传进去

?/**
? * 登录
? *
? * @param loginVo 用户名和密码
? * @return {@link String}
? */
?@PostMapping("/login")
?public String login(@RequestBody UserLoginVo loginVo) {
? ? ?SecurityUtils.getSubject().login(
        new UsernamePasswordToken(loginVo.getUserName(), loginVo.getPassWord()));
? ? ?System.out.println(loginVo);
? ? ?return "登录成功";
?}

????????然后通过接口测试工具来调用/login接口,通过debug发现,的确进入了我们所定义的方法

????????此时,我们再次调用/hello接口,然后可以发现,可以返回我们需要的数据

5、优化

????????在上述,当未认证时,访问接口,前端则会报 500 错误。此时,我们可以定义个全局异常捕获,让报错更加的优雅。

?package com.hsx.utils;
??
?import org.apache.shiro.authz.AuthorizationException;
?import org.apache.shiro.authz.UnauthenticatedException;
?import org.springframework.web.bind.annotation.ExceptionHandler;
?import org.springframework.web.bind.annotation.RestControllerAdvice;
??
?import javax.servlet.http.HttpServletRequest;
?import javax.servlet.http.HttpServletResponse;
??
??
?@RestControllerAdvice
?public class BaseExceptionHandler {
??
? ? ?/**
? ? ? * 处理未授权的异常
? ? ? */
? ? ?@ExceptionHandler(value = AuthorizationException.class)
? ? ?public String returnErrorMsg(HttpServletRequest request, HttpServletResponse response, AuthorizationException exception) {
? ? ? ? ?return "您没有权限";
? ?  }
??
? ? ?/**
? ? ? * 处理未登录的异常
? ? ? */
? ? ?@ExceptionHandler(value = UnauthenticatedException.class)
? ? ?public String returnUnLoginErrorMsg(HttpServletRequest request, HttpServletResponse response, UnauthenticatedException exception) {
??
? ? ? ? ?return "您还未登录";
? ?  }
??
??
? ? ?/**
? ? ? * 处理运行时异常
? ? ? */
? ? ?@ExceptionHandler(value = Exception.class)
? ? ?public String returnRunningException(Exception e) {
? ? ? ? ?System.out.println(e.getMessage());
? ? ? ? ?return "系统错误";
? ?  }
??
?}

????????此时,再次访问没有权限的接口。

总结

????????上述代码,可以先根据我的步骤来实现,然后对比oj系统中相应部分的实现。其实原理都是一样的。不一样的地方,比如在认证方法doGetAuthenticationInfo那里,我为了方便,就是将账号密码写死,而在oj系统中,是进行了JWT反解析获取到用户ID,然后去数据库查询用户是否存在,最后才进行密码的比较。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-10-08 20:27:04  更:2022-10-08 20:29:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年3日历 -2025/3/10 15:23:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码