Springboot整合之Shiro和JWT技术实现无感刷新9

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
简介: Springboot整合之Shiro和JWT技术实现无感刷新9

4.5 创建OAuth2Filter类

注意事项:

    因为在 OAuth2Filter 类中要读写 ThreadLocal 中的数据,所以 OAuth2Filter 类必 须要设置成多例的,否则 ThreadLocal 将无法使用。

```package com.example.emos.wx.config.shiro;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import org.apache.http.HttpStatus;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Component
@Scope("prototype")
public class OAuth2Filter extends AuthenticatingFilter {
@Autowired
private ThreadLocalToken threadLocalToken;

@Value("${emos.jwt.cache-expire}")
private int cacheExpire;

@Autowired
private JwtUtil jwtUtil;

@Autowired
private RedisTemplate redisTemplate;

/**
* 拦截请求之后,用于把令牌字符串封装成令牌对象
*/
@Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
    HttpServletRequest req= (HttpServletRequest) request;
    String token=getRequestToken(req);
    if(StrUtil.isBlank(token)){
        return null;
    }
    return new OAuth2Token(token);
}

/**
* 拦截请求,判断请求是否需要被Shiro处理
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
    // Ajax提交application/json数据的时候,会先发出Options请求
    HttpServletRequest req= (HttpServletRequest) request;
    if(req.getMethod().equals(RequestMethod.OPTIONS.name())){
        return true;
    }
    return false;
}

/**
*     该方法用于处理所有应该被Shiro处理的请求
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
    HttpServletRequest req= (HttpServletRequest) request;
    HttpServletResponse resp= (HttpServletResponse) response;
    resp.setContentType("text/html");
    resp.setCharacterEncoding("UTF-8");
    resp.setHeader("Access-Control-Allow-Credentials", "true");
    resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));

    threadLocalToken.clear();
    //获取请求token,如果token不存在,直接返回401
    String token=getRequestToken(req);
    if(StrUtil.isBlank(token)){
        resp.setStatus(HttpStatus.SC_UNAUTHORIZED);
        resp.getWriter().print("无效的令牌");
        return false;
    }
    try{
        jwtUtil.verifierToken(token);
    }catch (TokenExpiredException e){
        //客户端令牌过期,查询Redis中是否存在令牌,如果存在令牌就重新生成一个令牌给客户端
        if(redisTemplate.hasKey(token)){
            redisTemplate.delete(token);
            int userId=jwtUtil.getUserId(token);
            token=jwtUtil.createToken(userId);
            redisTemplate.opsForValue().set(token,userId+"",cacheExpire, TimeUnit.DAYS);
            //把新令牌绑定到线程
            threadLocalToken.setToken(token);
        }
        else{
            //如果Redis不存在令牌,让用户重新登录
            resp.setStatus(HttpStatus.SC_UNAUTHORIZED);
            resp.getWriter().print("令牌已过期");
            return false;
        }
    }catch (Exception e){
        resp.setStatus(HttpStatus.SC_UNAUTHORIZED);
        resp.getWriter().print("无效的令牌");
        return false;
    }
    boolean bool=executeLogin(request,response);
    return bool;
}

@Override
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
    HttpServletRequest req= (HttpServletRequest) request;
    HttpServletResponse resp= (HttpServletResponse) response;
    resp.setContentType("text/html");
    resp.setCharacterEncoding("UTF-8");
    resp.setHeader("Access-Control-Allow-Credentials", "true");
    resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
    resp.setStatus(HttpStatus.SC_UNAUTHORIZED);
    try{
        resp.getWriter().print(e.getMessage());
    }catch (Exception exception){

    }

    return false;
}

@Override
public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
    HttpServletRequest req= (HttpServletRequest) request;
    HttpServletResponse resp= (HttpServletResponse) response;
    resp.setContentType("text/html");
    resp.setCharacterEncoding("UTF-8");
    resp.setHeader("Access-Control-Allow-Credentials", "true");
    resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
    super.doFilterInternal(request, response, chain);

}
/**
* 获取请求头里面的token
*/
private String getRequestToken(HttpServletRequest request){
    String token=request.getHeader("token");
    if(StrUtil.isBlank(token)){
        token=request.getParameter("token");
    }
    return token;
}

}
```

4.6 创建ShiroConfig类

    我们要创建的 ShiroConfig 类,是用来把 OAuth2Filter 和 OAuth2Realm 配置到Shiro框架,这 样我们辛苦搭建的Shiro+JWT才算生效。

4.7 利用AOP,把更新的令牌返回给客户端

    我们在写 OAuth2Filter 的时候,把更新后的令牌写到 ThreadLocalToken 里面的 ThreadLocal 。那么这个小节,我们要创建 AOP切面类 ,拦截所有Web方法的返回值,在返回 的 R对象 中添加更新后的令牌。

————————————————

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
5月前
|
JSON 安全 Java
什么是JWT?如何使用Spring Boot Security实现它?
什么是JWT?如何使用Spring Boot Security实现它?
1094 5
|
2月前
|
安全 Java Apache
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 身份和权限认证
本文介绍了 Apache Shiro 的身份认证与权限认证机制。在身份认证部分,分析了 Shiro 的认证流程,包括应用程序调用 `Subject.login(token)` 方法、SecurityManager 接管认证以及通过 Realm 进行具体的安全验证。权限认证部分阐述了权限(permission)、角色(role)和用户(user)三者的关系,其中用户可拥有多个角色,角色则对应不同的权限组合,例如普通用户仅能查看或添加信息,而管理员可执行所有操作。
109 0
|
2月前
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
115 0
|
1月前
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
231 70
|
4月前
|
缓存 安全 Java
Spring Boot 3 集成 Spring Security + JWT
本文详细介绍了如何使用Spring Boot 3和Spring Security集成JWT,实现前后端分离的安全认证概述了从入门到引入数据库,再到使用JWT的完整流程。列举了项目中用到的关键依赖,如MyBatis-Plus、Hutool等。简要提及了系统配置表、部门表、字典表等表结构。使用Hutool-jwt工具类进行JWT校验。配置忽略路径、禁用CSRF、添加JWT校验过滤器等。实现登录接口,返回token等信息。
1857 13
|
4月前
|
XML JavaScript Java
SpringBoot集成Shiro权限+Jwt认证
本文主要描述如何快速基于SpringBoot 2.5.X版本集成Shiro+JWT框架,让大家快速实现无状态登陆和接口权限认证主体框架,具体业务细节未实现,大家按照实际项目补充。
279 11
|
5月前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
295 1
|
6月前
|
JSON 安全 算法
Spring Boot 应用如何实现 JWT 认证?
Spring Boot 应用如何实现 JWT 认证?
173 8
|
6月前
|
JavaScript NoSQL Java
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
149 0
|
15天前
|
JavaScript 前端开发 Java
制造业ERP源码,工厂ERP管理系统,前端框架:Vue,后端框架:SpringBoot
这是一套基于SpringBoot+Vue技术栈开发的ERP企业管理系统,采用Java语言与vscode工具。系统涵盖采购/销售、出入库、生产、品质管理等功能,整合客户与供应商数据,支持在线协同和业务全流程管控。同时提供主数据管理、权限控制、工作流审批、报表自定义及打印、在线报表开发和自定义表单功能,助力企业实现高效自动化管理,并通过UniAPP实现移动端支持,满足多场景应用需求。