最近在做项目的过程中 需要用JWT做登录和鉴权 查了很多资料 都不甚详细
有的是需要在application.yml里进行jwt的配置 但我在导包后并没有相应的配置项 因而并不适用
在踩过很多坑之后 稍微整理了一下 做个笔记
Json Web Token (JWT)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519)
该token被设计为紧凑且安全的 特别适用于分布式站点的单点登录(SSO)场景
随着JWT的出现 使得校验方式更加简单便捷化
JWT实际上就是一个字符串 它由三部分组成:头部 载荷和签名
用[ .
]分隔这三个部分 最终的格式类似于: xxxx.xxxx.xxxx
在服务器直接根据token取出保存的用户信息 即可对token的可用性进行校验 使得单点登录更为简单
2、JWT校验的过程
1、浏览器发送用户名和密码 发起登录请求
2、服务端验证身份 根据算法将用户标识符打包生成token字符串 并且返回给浏览器
3、当浏览器需要发起请求时 将token一起发送给服务器
4、服务器发现数据中携带有token 随即进行解密和鉴权
5、校验成功 服务器返回请求的数据
<!-- Spring Security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- Spring Security和JWT整合 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> <version>1.0.10.RELEASE</version> </dependency> <!-- JWT --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <!-- 字符串转换需要用到此包 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency>
两个实体类 一个是用户 另一个是权限
public class User { private Integer id; private String username; private String password; 省略gettersetter之类的代码... }
public class Role { private Integer id; private String username; private String name; 省略gettersetter之类的代码... }
该类用于进行Token的加密和解密 可在此类中单元测试
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.util.Date; import java.util.HashMap; import java.util.Map; public class JwtTokenUtil { // Token请求头 public static final String TOKEN_HEADER = "Authorization"; // Token前缀 public static final String TOKEN_PREFIX = "Bearer "; // 签名主题 public static final String SUBJECT = "piconjo"; // 过期时间 public static final long EXPIRITION = 1000 * 24 * 60 * 60 * 7; // 应用密钥 public static final String APPSECRET_KEY = "piconjo_secret"; // 角色权限声明 private static final String ROLE_CLAIMS = "role"; /** * 生成Token */ public static String createToken(String username,String role) { Map<String,Object> map = new HashMap<>(); map.put(ROLE_CLAIMS, role); String token = Jwts .builder() .setSubject(username) .setClaims(map) .claim("username",username) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + EXPIRITION)) .signWith(SignatureAlgorithm.HS256, APPSECRET_KEY).compact(); return token; } /** * 校验Token */ public static Claims checkJWT(String token) { try { final Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody(); return claims; } catch (Exception e) { e.printStackTrace(); return null; } } /** * 从Token中获取username */ public static String getUsername(String token){ Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody(); return claims.get("username").toString(); } /** * 从Token中获取用户角色 */ public static String getUserRole(String token){ Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody(); return claims.get("role").toString(); } /** * 校验Token是否过期 */ public static boolean isExpiration(String token){ Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody(); return claims.getExpiration().before(new Date()); } }
import xxx.xxx.xxx.bean.Role; // 自己的包 import xxx.xxx.xxx.bean.User; // 自己的包 import xxx.xxx.xxx.mapper.UserMapper; // 自己的包 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; @Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { if (s == null || "".equals(s)) { throw new RuntimeException("用户不能为空"); } // 调用方法查询用户 User user = userMapper.findUserByUsername(s); if (user == null) { throw new RuntimeException("用户不存在"); } List<SimpleGrantedAuthority> authorities = new ArrayList<>(); for (Role role:userMapper.findRoleByUsername(s)) { authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName())); } return new org.springframework.security.core.userdetails.User(user.getUsername(),"{noop}"+user.getPassword(),authorities); } }
其中 一个用于登录 另一个用于鉴权
JWTAuthenticationFilter登录拦截器:
该拦截器用于获取用户登录的信息
至于具体的验证 只需创建一个token并调用authenticationManager的authenticate()方法
让Spring security验证即可 验证的事交给框架
import com.alibaba.fastjson.JSON; import xxx.xxx.xxx.utils.JwtTokenUtil; // 自己的包 import org.springframework.security.authentication.*; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Collection; /** * 验证用户名密码正确后 生成一个token并将token返回给客户端 */ public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter { private AuthenticationManager authenticationManager; public JWTAuthenticationFilter(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; } /** * 验证操作 接收并解析用户凭证 */ @Override public Authentication attemptAuthentication(HttpServletRequest request,HttpServletResponse response) throws AuthenticationException { // 从输入流中获取到登录的信息 // 创建一个token并调用authenticationManager.authenticate() 让Spring security进行验证 return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(request.getParameter("username"),request.getParameter("password"))); } /** * 验证【成功】后调用的方法 * 若验证成功 生成token并返回 */ @Override protected void successfulAuthentication(HttpServletRequest request,HttpServletResponse response,FilterChain chain,Authentication authResult) throws IOException { User user= (User) authResult.getPrincipal(); // 从User中获取权限信息 Collection<? extends GrantedAuthority> authorities = user.getAuthorities(); // 创建Token String token = JwtTokenUtil.createToken(user.getUsername(), authorities.toString()); // 设置编码 防止乱码问题 response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); // 在请求头里返回创建成功的token // 设置请求头为带有"Bearer "前缀的token字符串 response.setHeader("token", JwtTokenUtil.TOKEN_PREFIX + token); // 处理编码方式 防止中文乱码 response.setContentType("text/json;charset=utf-8"); // 将反馈塞到HttpServletResponse中返回给前台 response.getWriter().write(JSON.toJSONString("登录成功")); } /** * 验证【失败】调用的方法 */ @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { String returnData=""; // 账号过期 if (failed instanceof AccountExpiredException) { returnData="账号过期"; } // 密码错误 else if (failed instanceof BadCredentialsException) { returnData="密码错误"; } // 密码过期 else if (failed instanceof CredentialsExpiredException) { returnData="密码过期"; } // 账号不可用 else if (failed instanceof DisabledException) { returnData="账号不可用"; } //账号锁定 else if (failed instanceof LockedException) { returnData="账号锁定"; } // 用户不存在 else if (failed instanceof InternalAuthenticationServiceException) { returnData="用户不存在"; } // 其他错误 else{ returnData="未知异常"; } // 处理编码方式 防止中文乱码 response.setContentType("text/json;charset=utf-8"); // 将反馈塞到HttpServletResponse中返回给前台 response.getWriter().write(JSON.toJSONString(returnData)); } }
当访问需要权限校验的URL(当然 该URL也是需要经过配置的) 则会来到此拦截器 在该拦截器中对传来的Token进行校验
只需告诉Spring security该用户是否已登录 并且是什么角色 拥有什么权限即可
import xxx.xxx.xxx.utils.JwtTokenUtil; // 自己的包 import org.apache.commons.lang3.StringUtils; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; /** * 登录成功后 走此类进行鉴权操作 */ public class JWTAuthorizationFilter extends BasicAuthenticationFilter { public JWTAuthorizationFilter(AuthenticationManager authenticationManager) { super(authenticationManager); } /** * 在过滤之前和之后执行的事件 */ @Override protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain) throws IOException, ServletException { String tokenHeader = request.getHeader(JwtTokenUtil.TOKEN_HEADER); // 若请求头中没有Authorization信息 或是Authorization不以Bearer开头 则直接放行 if (tokenHeader == null || !tokenHeader.startsWith(JwtTokenUtil.TOKEN_PREFIX)) { chain.doFilter(request, response); return; } // 若请求头中有token 则调用下面的方法进行解析 并设置认证信息 SecurityContextHolder.getContext().setAuthentication(getAuthentication(tokenHeader)); super.doFilterInternal(request, response, chain); } /** * 从token中获取用户信息并新建一个token * * @param tokenHeader 字符串形式的Token请求头 * @return 带用户名和密码以及权限的Authentication */ private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader) { // 去掉前缀 获取Token字符串 String token = tokenHeader.replace(JwtTokenUtil.TOKEN_PREFIX, ""); // 从Token中解密获取用户名 String username = JwtTokenUtil.getUsername(token); // 从Token中解密获取用户角色 String role = JwtTokenUtil.getUserRole(token); // 将[ROLE_XXX,ROLE_YYY]格式的角色字符串转换为数组 String[] roles = StringUtils.strip(role, "[]").split(", "); Collection<SimpleGrantedAuthority> authorities=new ArrayList<>(); for (String s:roles) { authorities.add(new SimpleGrantedAuthority(s)); } if (username != null) { return new UsernamePasswordAuthenticationToken(username, null,authorities); } return null; } }
该类需实现AuthenticationEntryPoint
import com.alibaba.fastjson.JSONObject; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class JWTAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { response.setCharacterEncoding("utf-8"); response.setContentType("text/javascript;charset=utf-8"); response.getWriter().print(JSONObject.toJSONString("您未登录,没有访问权限")); } }
创建一个自定义的配置类 继承WebSecurityConfigurerAdapter
在该类上 需加 @EnableWebSecurity
注解 配置Web安全过滤器和启用全局认证机制
import xxx.xxx.xxx.JWTAuthenticationEntryPoint; // 自己的包 import xxx.xxx.xxx.xxx.JWTAuthenticationFilter; // 自己的包 import xxx.xxx.xxx.xxx.JWTAuthorizationFilter; // 自己的包 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired @Qualifier("userDetailsServiceImpl") private UserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); } /** * 安全配置 */ @Override protected void configure(HttpSecurity http) throws Exception { // 跨域共享 http.cors() .and() // 跨域伪造请求限制无效 .csrf().disable() .authorizeRequests() // 访问/data需要ADMIN角色 .antMatchers("/data").hasRole("ADMIN") // 其余资源任何人都可访问 .anyRequest().permitAll() .and() // 添加JWT登录拦截器 .addFilter(new JWTAuthenticationFilter(authenticationManager())) // 添加JWT鉴权拦截器 .addFilter(new JWTAuthorizationFilter(authenticationManager())) .sessionManagement() // 设置Session的创建策略为:Spring Security永不创建HttpSession 不使用HttpSession来获取SecurityContext .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() // 异常处理 .exceptionHandling() // 匿名用户访问无权限资源时的异常 .authenticationEntryPoint(new JWTAuthenticationEntryPoint()); } /** * 跨域配置 * @return 基于URL的跨域配置信息 */ @Bean CorsConfigurationSource corsConfigurationSource() { final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); // 注册跨域配置 source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues()); return source; } }
定义一个用于测试的对外映射接口:
@RestController public class UserController { @GetMapping("/data") private ResponseUtil data() { return "This is data."; } }
默认登录路径是 /login
用POST请求发送
若要修改默认的登录路径 只需要在自己定义的登录过滤器JWTAuthenticationFilter的构造方法里进行配置即可
比如 若想修改为/api/login:
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; // 设置登录URL super.setFilterProcessesUrl("/api/login"); }
登录时 参数的属性名分别是username和password 不能改动:
登录成功后会返回一个Token:
在请求需要权限的接口路径时 若不带上Token 则会提示没有访问权限
带上Token后再次请求 即可正常访问:
注:Token的前面要带有 Bearer
的前缀
这样 一个基本的实现就差不多完成了
为简单演示 在该案例中就不对密码进行加密了 实际开发是需要对明文密码加密后存储的 推荐用BCrypt进行加密和解密
为节省篇幅 用于注册的接口也不写了 实际上在注册接口传入的密码也需要用BCrypt加密后再存入数据库中
还可以用Redis进行Token的存储 这些都是后话了
到此这篇关于SpringBoot集成Spring Security用JWT令牌实现登录和鉴权的方法的文章就介绍到这了,更多相关SpringBoot JWT令牌登录和鉴权内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
时间:2020-05-17
摘要:用spring-boot开发RESTful API非常的方便,在生产环境中,对发布的API增加授权保护是非常必要的.现在我们来看如何利用JWT技术为API增加授权保护,保证只有获得授权的用户才能够访问API. 一:开发一个简单的API 在IDEA开发工具中新建一个maven工程,添加对应的依赖如下: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-b
JWT简介 简介 JSON Web token简称JWT, 是用于对应用程序上的用户进行身份验证的标记.也就是说, 使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他session数据.此特性便于可伸缩性, 同时保证应用程序的安全. 在身份验证过程中, 当用户使用其凭据成功登录时, 将返回 JSON Web token, 并且必须在本地保存 (通常在本地存储中).每当用户要访问受保护的路由或资源 (端点) 时, 用户代理(user agent)必须连同请求一起发送 JWT,
原来一直使用shiro做安全框架,配置起来相当方便,正好有机会接触下SpringSecurity,学习下这个.顺道结合下jwt,把安全信息管理的问题扔给客户端, 准备 首先用的是SpringBoot,省去写各种xml的时间.然后把依赖加入一下 <!--安全--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-secu
前言 最近我们组要给负责的一个管理系统 A 集成另外一个系统 B,为了让用户使用更加便捷,避免多个系统重复登录,希望能够达到这样的效果--用户只需登录一次就能够在这两个系统中进行操作.很明显这就是单点登录(Single Sign-On)达到的效果,正好可以明目张胆的学一波单点登录知识. 本篇主要内容如下: SSO 介绍 SSO 的几种实现方式对比 基于 JWT 的 spring boot 单点登录实战 注意: SSO 这个概念已经出现很久很久了,目前各种平台都有非常成熟的实现,比如OpenSSO
本教程主要详细讲解SpringBoot Security整合JWT授权RestAPI. 基础环境 技术 版本 Java 1.8+ SpringBoot 2.x.x Security 5.x JWT 0.9.0 创建项目 初始化项目 mvn archetype:generate -DgroupId=com.edurt.sli.slisj -DartifactId=spring-learn-integration-security-jwt -DarchetypeArtifactId=maven-ar
JWT官网: https://jwt.io/ JWT(Java版)的github地址:https://github.com/jwtk/jjwt 什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).定义了一种简洁的,自包含的方法用于通信双方之间以JSON对象的形式安全的传递信息.因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名. JWT请求流程 1. 用户使
本文实例为大家分享了Spring boot整合shiro+jwt实现前后端分离的具体代码,供大家参考,具体内容如下 这里内容很少很多都为贴的代码,具体内容我经过了看源码和帖子加了注释.帖子就没用太多的内容 先下载shiro和jwt的jar包 <!-- shiro包 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId
本文介绍了spring Boot实战之Filter实现使用JWT进行接口认证,分享给大家 jwt(json web token) 用户发送按照约定,向服务端发送 Header.Payload 和 Signature,并包含认证信息(密码),验证通过后服务端返回一个token,之后用户使用该token作为登录凭证,适合于移动端和api jwt使用流程 本文示例接上面几篇文章中的代码进行编写,请阅读本文的同时可以参考前面几篇文章 1.添加依赖库jjwt,本文中构造jwt及解析jwt都使用了jjwt库
GitHub源码地址:https://github.com/zeng-xian-guo/springboot_jwt_token.git 封装JTW生成token和校验方法 public class JwtTokenUtil { //公用密钥-保存在服务端,客户端是不会知道密钥的,以防被攻击 public static String SECRET = "ThisIsASecret"; //生成Troke public static String createToken(String u
这篇文章主要介绍了SpringBoot实现拦截器.过滤器.监听器过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 过滤器 过滤器简介 过滤器的英文名称为 Filter, 是 Servlet 技术中最实用的技术.如同它的名字一样,过滤器是处于客户端和服务器资源文件之间的一道过滤网,帮助我们过滤掉一些不符合要求的请求,通常用作 Session 校验,判断用户权限,如果不符合设定条件,则会被拦截到特殊的地址或者基于特殊的响应. 过滤器的使用 首
这篇文章主要介绍了springboot使用war包部署到外部tomcat过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 如果是war包部署到外部tomcat,需要增加SpringBootServletInitializer子类,并重写其configure方法,或者将main函数所在的类继承SpringBootServletInitializer子类,并重写configure方法. @SpringBootApplication //继承S
这篇文章主要介绍了Java对象转json的方法过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1. jsonlib:个人感觉最麻烦的一个需要导入的包也多,代码也相对多一些. 2.Gson:google的 3.FastJson:阿里巴巴的,个人觉得这个比较好,而且据说这个也是性能最好一个. 下面就贴出三种写法的代码,读者可以任选其一去使用.关于demo里面所使用的jar包,可以自行去下载. Jsonlib: package json; i
这篇文章主要介绍了springboot中将日志信息存储在catalina.base中过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 <?xml version="1.0" encoding="UTF-8"?> <configuration debug="true"> <!-- 项目名称 --> <property name="PROJE
这篇文章主要介绍了调用其他python脚本文件里面的类和方法过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 问题描述: 自己编写了若干个Python脚本. 在testC.py里面需要调用testA.py和testB.py里面的若干类和方法.要怎么办? 需要都打包.安装,再去调用吗? 其实不必那么麻烦. 这里有个前提,testA.py, testB.py, testC.py在同级目录下. 如果不在同级目录,后面会补充介绍如何把路径包含过来
这篇文章主要介绍了Java自定义实现equals()方法过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 以常见的自定义Date类型为例,没有经验的朋友可能会觉得直接比较年月日即可,从而写出以下的实现 public class MyDate implements Comparable<MyDate> { private final int year; private final int month; private final int
我们提供Restful接口的时候,API文档是尤为的重要,它承载着对接口的定义,描述等.它还是和API消费方沟通的重要工具.在实际情况中由于接口和文档存放的位置不同,我们很难及时的去维护文档.个人在实际的工作中就遇到过很多接口更新了很久,但是文档却还是老版本的情况,其实在这个时候这份文档就已经失去了它存在的意义.而 Swagger 是目前我见过的最好的API文档生成工具,使用起来也很方便,还可以直接调试我们的API.我们今天就来看下 Swagger2 与 SpringBoot 的结合. 准备工作
什么是JWT JSON Web Token(JWT)是一个开放的标准(RFC 7519),它定义了一个紧凑且自包含的方式,用于在各方之间以JSON对象安全地传输信息.这些信息可以通过数字签名进行验证和信任.可以使用秘密(使用HMAC算法)或使用RSA的公钥/私钥对来对JWT进行签名. 具体的jwt介绍可以查看官网的介绍:https://jwt.io/introduction/ jwt请求流程 引用官网的图片 中文介绍: 用户使用账号和面发出post请求: 服务器使用私钥创建一个jwt: 服务器返
上篇 <SpringBoot 集成 redis 分布式锁优化>对死锁的问题进行了优化,今天介绍的是 redis 官方推荐使用的 Redisson ,Redisson 架设在 redis 基础上的 Java 驻内存数据网格(In-Memory Data Grid),基于NIO的 Netty 框架上,利用了 redis 键值数据库.功能非常强大,解决了很多分布式架构中的问题. Github的wiki地址: https://github.com/redisson/redisson/wiki 官方文档