欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

jwt获取token_JWT实现token认证

发布时间:2023/12/10 编程问答 55 豆豆
生活随笔 收集整理的这篇文章主要介绍了 jwt获取token_JWT实现token认证 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

1.JWT是什么?

Json Web Token(JWT)是目前比较流行的跨域认证解决方案,是一种基于JSON的开发标准,由于数据是可以经过签名加密的,比较安全可靠,一般用于前端和服务器之间传递信息,也可以用在移动端和后台传递认证信息。

2.JWT的组成

让我们先来看看jwt的实际例子:

Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2wiOiJST0xFXzEiLCJpc3MiOiJTbmFpbENsaW1iIiwiaWF0IjoxNTk1OTkzMDQwLCJzdWIiOiIxNTAwMDAwMDAwMCIsImV4cCI6MTU5NjU5Nzg0MH0.Wxet2qPG1ajyG9CcQCN29gfKJzal0vCmQSXrwAgQwcI

我们可以看到,这个JWT包含3部分,是由“.”号分开的,Bearer是jwt中的一种前缀规范。

第一部分是Header:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

第二部分是Payload:

eyJyb2wiOiJST0xFXzEiLCJpc3MiOiJTbmFpbENsaW1iIiwiaWF0IjoxNTk2MDAzODM4LCJzdWIiOiIxNTAwMDAwMDAwMCIsImV4cCI6MTU5NjYwODYzOH0

第三方部分是签名Signature:

MJmTSGBM9wRVOY40ORZuSGpT7FQNUcD2JlJxL0K0-YM

3.JWT的流程

先上图:

  • 客户端登录接口输入用户名和密码提交到服务器;

  • 服务器端校验用户名和密码,校验通过则创建一个JWT;

  • 服务器端返回该JWT给客户端;

  • 客户端每请求一次接口在Headers中带上返回的JWT;

  • JWT自身的算法校验该JWT;

  • 如果校验通过,操作DB,返回数据;反之返回状态码和错误信息。

  • 4.SpringBoot集成JWT,代码实现

    引入jwt的依赖库:

    <dependency> <groupId>io.jsonwebtokengroupId> <artifactId>jjwt-apiartifactId> <version>0.10.7version> dependency> <dependency> <groupId>io.jsonwebtokengroupId> <artifactId>jjwt-implartifactId> <version>0.10.7version> <scope>runtimescope> dependency> <dependency> <groupId>io.jsonwebtokengroupId> <artifactId>jjwt-jacksonartifactId> <version>0.10.7version> <scope>runtimescope> dependency>

    JwtTokenUtils类:用于生成token

    /** * @author kevincow */public class JwtTokenUtils { /** * 生成足够的安全随机密钥,以适合符合规范的签名 */ private static byte[] apiKeySecretBytes = Base64.getDecoder().decode(SecurityConstants.JWT_SECRET_KEY); private static SecretKey secretKey = Keys.hmacShaKeyFor(apiKeySecretBytes); public static String createToken(String username, List<String> roles) { long expiration = SecurityConstants.EXPIRATION_REMEMBER; String tokenPrefix = Jwts.builder() .setHeaderParam("typ", SecurityConstants.TOKEN_TYPE) .signWith(secretKey, SignatureAlgorithm.HS256) .claim(SecurityConstants.ROLE_CLAIMS, String.join(",", roles)) .setIssuer("SnailClimb") .setIssuedAt(new Date()) .setSubject(username) .setExpiration(new Date(System.currentTimeMillis() + expiration * 1000)) .compact(); return SecurityConstants.TOKEN_PREFIX + tokenPrefix; }}

    接下来需要写一个过滤器去实现token的校验功能:

    /** * 实现token的校验功能 * * 过滤器处理所有HTTP请求,并检查是否存在带有正确令牌的Authorization标头。例如,如果令牌未过期或签名密钥正确。 * * @author kevincow */public class JWTAuthorizationFilter extends BasicAuthenticationFilter { private static final Logger logger = Logger.getLogger(JWTAuthorizationFilter.class.getName()); public JWTAuthorizationFilter(AuthenticationManager authenticationManager) { super(authenticationManager); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { logger.info("token"+request.getHeader(SecurityConstants.TOKEN_HEADER)); String authorization = request.getHeader(SecurityConstants.TOKEN_HEADER); // 如果请求头中没有token信息则直接放行了 if (authorization == null || !authorization.startsWith(SecurityConstants.TOKEN_PREFIX)) { chain.doFilter(request, response); return; } // 如果请求头中有token,则进行解析,并且设置授权信息 SecurityContextHolder.getContext().setAuthentication(getAuthentication(authorization)); super.doFilterInternal(request, response, chain); } /** * 获取用户认证信息 Authentication */ private UsernamePasswordAuthenticationToken getAuthentication(String authorization) { String token = authorization.replace(SecurityConstants.TOKEN_PREFIX, ""); try { String username = JwtTokenUtils.getUsernameByToken(token); logger.info("checking username:" + username); // 通过 token 获取用户具有的角色 List userRolesByToken = JwtTokenUtils.getUserRolesByToken(token); if (!StringUtils.isEmpty(username)) { return new UsernamePasswordAuthenticationToken(username, null, userRolesByToken); } } catch (SignatureException | ExpiredJwtException | MalformedJwtException | IllegalArgumentException exception) { logger.warning("Request to parse JWT with invalid signature . Detail : " + exception.getMessage()); } return null; }}

    最后写业务实现代码了(这里只展示控制层代码,业务代码就不一一赘述)

    /**     * 微信端登录接口,在header中带上token * * @param userName * @param passWord     * @return 是否登录成功 */    @ApiOperation(value = "用户登录成功之后,在header中带上token",            notes = "校验用户名密码,校验完成之后,在header中带上token", httpMethod = "GET")    @PostMapping("/whetherIsSysUser")    public SuccessResponse whetherRegister(@ApiParam("用户名") @RequestParam String userName,                                           @ApiParam("密码") @RequestParam String passWord, HttpServletResponse response) { try { User user = userService.whetherRegister(userName, passWord); if (StringUtils.isEmpty(user)) { return SuccessResponse.of(false, "该用户未注册"); } JwtUser jwtUser = new JwtUser(user); List roles = jwtUser.getAuthorities() .stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.toList()); String token = JwtTokenUtils.createToken(user.getPhone(), roles); // Http Response Header 中返回 Token response.setHeader(SecurityConstants.TOKEN_HEADER, token); } catch (RuntimeException e) { e.printStackTrace(); return SuccessResponse.of(false, "该用户未注册"); } return SuccessResponse.of(true); }

    至此,代码实现部分差不多就完成了。接下来我们看下效果:

    上图可以看到,登录接口用户名密码校验通过之后在headers中返回了Authorization。

    然后当客户端请求其他接口并在请求头带上登录时返回的Authorization,就能正常响应了。

    如果没有带上Authorization呢?那么会报一个错。

    { "timestamp": "2020-07-29 15:38:23", "status": 401, "error": "Unauthorized", "message": "Full authentication is required to access this resource", "path": "/wx/users/showNewVersion"}

    以上就差不多是jwt的整个流程了。

    5.总结

        从特点中看优点:

    • JSON的通用性,决定了JWT是个跨语言的技术;

    • JWT token对于sessionid的方案来说,JWT可以携带任何我们想要用到的信息;

    • 安全性高,防止token伪造和篡改;

    • JWT token是自校验的形式,不需要任何其他请求和数据库操作,使我们系统管理会话更高效;

    • JWT不需要在服务端保存会话信息, 所以它易于应用的扩展

        从特点中找缺点:

    • 一旦成功签发JWT token,无法手动将其过期;

    • 在token签发后的有效时间内,JWT无法做到及时获取最新数据,例如修改密码后无感知;

    • 存储空间、网络流量开销更大;

    • 为了安全,JWT需要使用https协议,以免token泄露

    以上。

    我是凯文cow,念念不忘,必有回响。

    总结

    以上是生活随笔为你收集整理的jwt获取token_JWT实现token认证的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。