shiro登录成功后返回json_java:shiro应用篇——1

第十章 Springboot+Shiro+Jwt前后端分离鉴权

1、前后端分离会话问题

【1】问题追踪

前面我们实现分布式的会话缓存,但是我们发现此功能的实现是基于浏览的cookie机制,也就是说用户禁用cookie后,我们的系统会就会产生会话不同的问题

【2】解决方案

​ 我们的前端可能是web、Android、ios等应用,同时我们每一个接口都提供了无状态的应答方式,这里我们提供了基于JWT的token生成方案

1、用户登陆之后,获得此时会话的sessionId,使用JWT根据sessionId颁发签名并设置过期时间(与session过期时间相同)返回token2、将token保存到客户端本地,并且每次发送请求时都在header上携带JwtToken3、ShiroSessionManager继承DefaultWebSessionManager,重写getSessionId方法,从header上检测是否携带JwtToken,如果携带,则进行解码JwtToken,使用JwtToken中的jti作为SessionId。4、重写shiro的默认过滤器,使其支持jwtToken有效期校验、及对JSON的返回支持    JwtAuthcFilter:实现是否需要登录的过滤,拒绝时如果header上携带JwtToken,则返回对应json    JwtPermsFilter:实现是否有对应资源的过滤,拒绝时如果header上携带JwtToken,则返回对应json    JwtRolesFilter:实现是否有对应角色的过滤,拒绝时如果header上携带JwtToken,则返回对应json

2、JWT概述

JWT(JSON WEB TOKEN):JSON网络令牌,JWT是一个轻便的安全跨平台传输格式,定义了一个紧凑的自包含的方式在不同实体之间安全传输信息(JSON格式)。它是在Web环境下两个实体之间传输数据的一项标准。实际上传输的就是一个字符串。

  • 广义上:JWT是一个标准的名称;
  • 狭义上:JWT指的就是用来传递的那个token字符串

JWT由三部分构成:header(头部)、payload(载荷)和signature(签名)。

  1. Header

存储两个变量

  1. 秘钥(可以用来比对)
  2. 算法(也就是下面将Header和payload加密成Signature)
  3. payload

存储很多东西,基础信息有如下几个

  1. 签发人,也就是这个“令牌”归属于哪个用户。一般是userId
  2. 创建时间,也就是这个令牌是什么时候创建的
  3. 失效时间,也就是这个令牌什么时候失效(session的失效时间)
  4. 唯一标识,一般可以使用算法生成一个唯一标识(jti==>sessionId)
  5. Signature

这个是上面两个经过Header中的算法加密生成的,用于比对信息,防止篡改Header和payload

然后将这三个部分的信息经过加密生成一个JwtToken的字符串,发送给客户端,客户端保存在本地。当客户端发起请求的时候携带这个到服务端(可以是在cookie,可以是在header),在服务端进行验证,我们需要解密对于的payload的内容

3、集成JWT

【1】JwtProperties

​ 用于支持yaml文件配置的配置类

package com.itheima.shiro.config;import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import java.io.Serializable;/** * @Description:jw配置文件 */@Data@ConfigurationProperties(prefix = "itheima.framework.jwt")public class JwtProperties implements Serializable {    /**     * @Description 签名密码     */    private String hexEncodedSecretKey;}

【2】JwtTokenManager

负责令牌的颁发、解析、校验

package com.itheima.shiro.core.impl;import com.auth0.jwt.JWT;import com.auth0.jwt.JWTVerifier;import com.auth0.jwt.algorithms.Algorithm;import com.itheima.shiro.config.JwtProperties;import com.itheima.shiro.utils.EncodesUtil;import io.jsonwebtoken.Claims;import io.jsonwebtoken.JwtBuilder;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.stereotype.Service;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.UUID;@Service("jwtTokenManager")@EnableConfigurationProperties({JwtProperties.class})public class JwtTokenManager {    @Autowired    JwtProperties jwtProperties;    /**     * @Description 签发令牌     *      jwt字符串包括三个部分     *        1. header     *            -当前字符串的类型,一般都是“JWT”     *            -哪种算法加密,“HS256”或者其他的加密算法     *            所以一般都是固定的,没有什么变化     *        2. payload     *            一般有四个最常见的标准字段(下面有)     *            iat:签发时间,也就是这个jwt什么时候生成的     *            jti:JWT的唯一标识     *            iss:签发人,一般都是username或者userId     *            exp:过期时间     * @param iss 签发人     * @param ttlMillis 有效时间     * @param claims jwt中存储的一些非隐私信息     * @return     */    public String IssuedToken(String iss, long ttlMillis,String sessionId, Map claims) {        if (claims == null) {            claims = new HashMap<>();        }        long nowMillis = System.currentTimeMillis();        String base64EncodedSecretKey = EncodesUtil.encodeHex(jwtProperties.getBase64EncodedSecretKey().getBytes());        JwtBuilder builder = Jwts.builder()                .setClaims(claims)                .setId(sessionId)//2. 这个是JWT的唯一标识,一般设置成唯一的,这个方法可以生成唯一标识,此时存储的为sessionId,登录成功后回写                .setIssuedAt(new Date(nowMillis))//1. 这个地方就是以毫秒为单位,换算当前系统时间生成的iat                .setSubject(iss)//3. 签发人,也就是JWT是给谁的(逻辑上一般都是username或者userId)                .signWith(SignatureAlgorithm.HS256, base64EncodedSecretKey);//这个地方是生成jwt使用的算法和秘钥        if (ttlMillis >= 0) {            long expMillis = nowMillis + ttlMillis;            Date exp = new Date(expMillis);//4. 过期时间,这个也是使用毫秒生成的,使用当前时间+前面传入的持续时间生成            builder.setExpiration(exp);        }        return builder.compact();    }    /**     * @Description 解析令牌     * @param jwtToken 令牌     * @return     */    public Claims decodeToken(String jwtToken) {        String base64EncodedSecretKey = EncodesUtil.encodeHex(jwtProperties.getBase64EncodedSecretKey().getBytes());        // 得到 DefaultJwtParser        return Jwts.parser()                // 设置签名的秘钥                .setSigningKey(base64EncodedSecretKey)                // 设置需要解析的 jwt                .parseClaimsJws(jwtToken)                .getBody();    }    /**     * @Description 判断令牌是否合法     * @param jwtToken 令牌  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值