在SpringBoot中使用jwt实现token身份认证的实例代码
- jwt (JSON Web Tokens)
jwt结构
- 用(.)分割的三个部位组成
- 标头
- 有效载荷
- 签名
xxx.xxx.xxx
标头
- 标头通常由两部分组成:令牌的类型(JWT)和所使用的签名算法(例如 HMAC SHA256 或 RSA
{ "alg": "HS256", "typ": "JWT" }
- 然后,对该 JSON 进行Base64Url编码以形成 JWT 的第一部分。
有效载荷
- 令牌的第二部分是有效负载,其中包含声明。声明是关于实体(通常是用户)和附加数据的声明。索赔分为三种类型:注册索赔、公开索赔和私人索赔。
- 注册声明
- 这些是一组预定义的声明,不是强制性的,而是推荐的,以提供一组有用的、可互操作的声明。其中一些是: iss(发行者)、 exp(到期时间)、 sub(主题)、 aud(受众)等。
- 公共声明
- 这些可以由使用 JWT 的人随意定义。但为了避免冲突,它们应该在[IANA JSON Web Token Registry]中定义,或者定义为包含防冲突命名空间的 URI
- 私人声明
- 这些是为在同意使用它们的各方之间共享信息而创建的自定义声明,既不是注册声明也不是公开声明。
有效负载示例
{ "sub": "1234567890", "name": "John Doe", "admin": true }
- 然后对有效负载进行Base64Url编码以形成 JSON Web 令牌的第二部分。
请注意,对于签名令牌,此信息虽然受到防止篡改的保护,但任何人都可以读取。除非加密,否则请勿将秘密信息放入 JWT 的有效负载或标头元素中。
签名
- 要创建签名部分,您必须获取编码的标头、编码的有效负载、秘密、标头中指定的算法,然后对其进行签名。
使用HMAC SHA256算法,则将通过以下方式创建签名
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
签名用于验证消息在传输过程中没有发生更改,并且在使用私钥签名的令牌的情况下,它还可以验证 JWT 的发送者是否是其所说的人。
将所有内容放在一起
- 输出是三个由点分隔的 Base64-URL 字符串,可以在 HTML 和 HTTP 环境中轻松传递,同时与基于 XML 的标准(例如 SAML)相比更加紧凑。
- 下面显示了一个 JWT,它具有先前的标头和有效负载编码,并且使用密钥进行签名。
- 官网翻译的,先了解一点前置知识,开整!
使用
依赖
- pom.xml文件咱们先加入jwt的依赖
JwtTokenUtils工具类
public class JwtTokenUtils { // token私钥 private static final String TOKEN_SECRET = "jwtSECRET"; // token过期时长30分钟 private static final long EXPIRE_TIME = 1800L; // 单位为秒 /** * 生成用户token,设置token超时时间 * * @return 生成的token */ public static String createToken(LoginVo loginVo) { Date expireDate = new Date(System.currentTimeMillis() + EXPIRE_TIME * 1000); // 创建 Token 的 payload Map<String, Object> map = new HashMap<>(); map.put("alg", "HS256"); map.put("typ", "JWT"); // 生成 JWT Token String token = JWT.create() .withHeader(map)// 添加头部 .withClaim("account", loginVo.getAccount()) .withExpiresAt(expireDate) //超时设置,设置过期的日期 .withIssuedAt(new Date()) //签发时间 .sign(Algorithm.HMAC256(TOKEN_SECRET)); //SECRET加密 return token; } /** * 检验token是否正确 * @param token 需要校验的token * @return 校验是否成功 */ public static Map<String, Claim> verifyToken(String token) { DecodedJWT jwt = null; token = token.replace("Bearer ", ""); // 这里要去掉Bearer ,postman默认会加这个,导致匹配不上 try { //设置签名的加密算法:HMAC256 Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); // 私钥需要一致 JWTVerifier verifier = JWT.require(algorithm).build(); jwt = verifier.verify(token); } catch (Exception e) { // logger.error(e.getMessage()); // 还没安装log4j等日志依赖,先注释 // logger.error("token解码异常"); //解码异常则抛出异常 return null; } return jwt.getClaims(); } }
- createToken方法主要就是创建token,并把账号密码作为自定义声明添加到 JWT 的 payload 中,最终返回
- verifyToken方法其实就是解码 token 并将其转换成 DecodedJWT 对象,通过
getClaims()
方法获取 payload 中的所有声明信息,并以 Map 的形式返回,如果 token 不合法或者解码过程中出现异常,则返回 null,校验的效果。
- 注意Bearer 这个玩意
JwtFilter.java
@Component @WebFilter(filterName = "JwtFilter", urlPatterns = "/*") public class JwtFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("jwt初始化方法"); } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) req; final HttpServletResponse response = (HttpServletResponse) res; response.setCharacterEncoding("UTF-8"); final String token = request.getHeader("Authorization"); String requestPath = request.getRequestURI(); // 登录接口,直接放行 if (requestPath.contains("/user/login")) { chain.doFilter(request, response); return; } if ("OPTIONS".equals(request.getMethod())) { // 是否是 OPTIONS 请求 response.setStatus(HttpServletResponse.SC_OK); chain.doFilter(request, response); } else { if (token == null) { response.getWriter().write("没有令牌"); return; } Map<String, Claim> userData = JwtTokenUtils.verifyToken(token); // 检验 token if (userData == null) { response.getWriter().write("令牌非法"); return; } String account = userData.get("account").asString(); // 获取用户名 request.setAttribute("account", account); // 设置用户名 chain.doFilter(req, res); // 过滤成功 } } @Override public void destroy() { System.out.println("jwt销毁方法执行的逻辑"); } }
- 这其实就是一个过滤类,你请求接口前就会先到这里,执行相对应的逻辑。
- init: 初始化方法
- doFilter:过滤拦截方法(主要逻辑就写在这)
- destroy:销毁方法
注意
urlPatterns = "/*"
: 这个代表拦截所有的请求,我在doFilter
里面判断了包含/login
直接放行。意思就是登录接口直接放行,返回token
给前端,如果是别的请求则走对应逻辑。@Component
:这个需要加上,这样才能扫描到你这个类不然不生效的。或者你在启动类加上@ServletComponentScan(basePackages = "com.yjx.boot.config")
,我的过滤器是写在config
包下的。
LoginController
@Controller @RestController // 可处理 HTTP 请求的控制器,并且能够返回数据给客户端 @RequestMapping("/user") @RequiredArgsConstructor public class LoginController { private final AdminService adminService; // 用户登陆 @GetMapping("/login") ResultVO<Object> login(LoginVo loginVo) { Admin admin = new Admin(); admin.setAccount(loginVo.getAccount()); admin.setAdminPassword(loginVo.getAdminPassword()); // 查找是否有该管理员 Admin an = adminService.queryByAdmin(admin); if (an == null) { return ResultResponse.failure(ResultCodeEnum.INTERNAL_NOT_FOUND); } else { String token = JwtTokenUtils.createToken(loginVo); loginVo.setToken(token); an.setToken(token); return ResultResponse.success(an); } } @GetMapping("/secure/current_registrant") public String currentRegistrant(HttpServletRequest request) { System.out.println("request" + request); String id = request.getParameter("id"); String account = request.getParameter("account"); String user_password = request.getParameter("adminPassword"); return "当前用户信息: id=" + id + " ,account=" + account + " ,user_password=" + user_password; } }
- 代码部分就完事了,测试一下。
测试
- 我们请求下/secure/current_registrant接口,此时是没有token的。
正常,输出了我们想要的:没有令牌
- 我们先去请求/login,看看token以及用户信息会不会如我们所想 返回给我们呢?
很好,也拿到了我们想要的,token也返回了,我们复制一下这个token,我们再次请求/secure/current_registrant,并把token放入请求头,试试能不能成功
- 成功
我们来试试把token写错一个字母会输出什么。
我们在请求头不传入token呢
完事!测试成功!写的并没有很好 甚至可能有些地方都写错了,慢慢完善吧
以上就是在SpringBoot中使用jwt实现token身份认证的实例代码的详细内容,更多关于SpringBoot jwt实现token认证的资料请关注脚本之家其它相关文章!
- 基于SpringBoot整合oauth2实现token认证
- springboot+jwt实现token登陆权限认证的实现
- SpringBoot和Redis实现Token权限认证的实例讲解
- SpringBoot整合Sa-Token实现登录认证的示例代码
- SpringBoot整合token实现登录认证的示例代码
- SpringBoot使用Sa-Token实现登录认证
- SpringBoot使用Sa-Token实现权限认证
- Springboot微服务分布式框架Rouyi Cloud权限认证(登录流程之token解析)
- Springboot 如何使用 SaToken 进行登录认证、权限管理及路由规则接口拦截
- springBoot整合jwt实现token令牌认证的示例代码
相关文章
详解使用JavaMailSender给曾经心爱的她再中秋发送一封特别的邮件
网站的服务端向用户发邮件时,邮件中往往需要携带图片,链接等内容。所以为了方便起见,我们一般发送HTML格式的邮件,那么怎么去拼一个HTML格式的邮件呢?——Thymeleaf。开始之前,先新建一个SpringBoot项目,并添加需要用到的依赖。然后就可以继续往下了2022-09-09基于 SASL/SCRAM 让 Kafka 实现动态授权认证的方法
在大数据处理和分析中 Apache Kafka 已经成为了一个核心组件,本文将从零开始部署 ZooKeeper 和 Kafka 并通过配置 SASL/SCRAM 和 ACL(访问控制列表)来增强 Kafka 的安全性,需要的朋友可以参考下2024-07-07SpringBoot常见get/post请求参数处理、参数注解校验及参数自定义注解校验详解
这篇文章主要给大家介绍了关于SpringBoot常见get/post请求参数处理、参数注解校验及参数自定义注解校验的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下2022-03-03
最新评论