其他分享
首页 > 其他分享> > 承接上一篇,whale系统开篇,聊聊用户认证

承接上一篇,whale系统开篇,聊聊用户认证

作者:互联网

关于传统的session以及jwt的实战,你会了么,跟上老猫,一起聊聊用户认证

写在前面

上次老猫和大家说过想要开发一个系统,从简单的权限开始做起,有的网友表示还是挺支持的,但是有的网友嗤之以鼻,认为太简单了,不过也没事,简单归简单,主要的还是个人技术的一个整合和实战。

没错,系统的名称老猫也已经定义好了叫做whale,whale是鲸鱼的意思。其实没有别的意思,也是老猫拍脑袋想出来的,可能是受到docker图标的影响。另外的真要说有点啥么,那就是老猫希望这个系统是成长的,是演变的,能从简单的小鱼系统成长为遨游海洋的鲸鱼,当然猫也喜欢吃鱼,扯远了......本篇起,老猫正式开始养鱼。

用户认证

开篇我们当然从用户的登录认证开始说起,关于用户认证,老猫不晓得大家对此是否熟悉,有些同学可能有所研究,这里老猫还是得详细和大家聊聊。说起用户认证,大家比较有所耳闻的应该就是session认证以及token认证。

传统的Session认证

我们说http请求是无状态的。这句话什么意思?所谓无状态,就是指用户向服务器端发起多个请求,服务器并不会知道多次请求都是来源于同一个用户,这就是无状态。

那么如何让服务器知道我们来自是哪一个用户的请求呢?所以我们只能在服务器中存储一份用户的登录信息,这份登录信息会在响应的时候传给浏览器,并且告诉其保存为cookie,以便下次请求的时候发送给我们的应用,这样我们的应用就识别了请求来源于哪个用户,这也就是传统的session认证。简单地画了一下原理图,大概就长下面这样。

session存储

当然,传统的单体架构中的存储是session内存的存储,随着用户的增多,服务器开销增加,为了扩展,逐渐将session信息可以存入到redis中间件中。这也是扩展的一种方式。

聊聊这种方式的短板。

相对的,我们再来看看相关的token认证。

Token认证

我们直接说个大白话,什么叫做token认证,说白了其实就是暗号。 在一些数据传输之前,要先进行暗号的核对,不同的暗号被授权不同的数据操作。

说得稍微专业一些应该是这样, Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。 大致的流程如下,

session存储

聊聊这种方式相对于传统session的优势。

所以综合对比了一下,token认证的优势也就相当明显了,所以老猫后面的认证也将会基于token来实现。

关于JWT

其实jwt就是 Json web token 的简写,一般组成的形式是这样xxx.yyy.zzz。很明显,其实是分为三部分。第一部分称它为头部(header),第二部分称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).

  1. Registered claims: 这里有一组预定义的声明,它们不是强制的,但是推荐。比如:iss (issuer), exp (expiration time), sub (subject), aud (audience)等。
  2. Public claims : 可以随意定义。
  3. Private claims : 用于在同意使用它们的各方之间共享信息,并且不是注册的或公开的声明。

签名(Signature):为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然后对它们签名即可。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

签名是用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方是否为它所称的发送方。

放在一起进行加密之后即为如下:

jwt加密后

在  jwt.io Debugger 去decode操作之后我想大家就一目了然了,当然这个图来自官网。

解密

以上关于JWT的相关介绍,说明:关于以下介绍均来自于官网,大家如果觉得老猫翻译的有问题的话,可以自行去官网看一下,官网地址:https://jwt.io/introduction/

JWTUtil的封装实战

如果上述大家觉得还是比较模糊,老猫封装了一个JWTUtil的工具类,大家可以参考着去理解,具体代码如下:

/**
 * @author kdaddy@163.com
 * @date 2021/4/13 23:06
 */
public class JwtUtil {
    // 生成签名是所使用的秘钥
    private final String base64EncodedSecretKey;

    // 生成签名的时候所使用的加密算法
    private final SignatureAlgorithm signatureAlgorithm;

    public JwtUtil(String secretKey, SignatureAlgorithm signatureAlgorithm) {
        this.base64EncodedSecretKey = Base64.encodeBase64String(secretKey.getBytes());
        this.signatureAlgorithm = signatureAlgorithm;
    }
    /**
     * 生成 JWT Token 字符串
     * @param iss       签发人名称
     * @param ttlMillis jwt 过期时间
     * @param claims    额外添加到荷部分的信息。
     *                  例如可以添加用户名、用户ID、用户(加密前的)密码等信息
     */
    public String encode(String iss, long ttlMillis, Mapclaims) {
        if (claims == null) {
            claims = new HashMap<>();
        }

        // 签发时间(iat):荷载部分的标准字段之一
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        // 下面就是在为payload添加各种标准声明和私有声明了
        JwtBuilder builder = Jwts.builder()
                // 荷载部分的非标准字段/附加字段,一般写在标准的字段之前。
                .setClaims(claims)
                // JWT ID(jti):荷载部分的标准字段之一,JWT 的唯一性标识,虽不强求,但尽量确保其唯一性。
                .setId(UUID.randomUUID().toString())
                // 签发时间(iat):荷载部分的标准字段之一,代表这个 JWT 的生成时间。
                .setIssuedAt(now)
                // 签发人(iss):荷载部分的标准字段之一,代表这个 JWT 的所有者。通常是 username、userid 这样具有用户代表性的内容。
                .setSubject(iss)
                // 设置生成签名的算法和秘钥
                .signWith(signatureAlgorithm, base64EncodedSecretKey);

        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            // 过期时间(exp):荷载部分的标准字段之一,代表这个 JWT 的有效期。
            builder.setExpiration(exp);
        }
        return builder.compact();
    }

    /**
     * JWT Token 由 头部 荷载部 和 签名部 三部分组成。签名部分是由加密算法生成,无法反向解密。
     * 而 头部 和 荷载部分是由 Base64 编码算法生成,是可以反向反编码回原样的。
     * 这也是为什么不要在 JWT Token 中放敏感数据的原因。
     * @param jwtToken 加密后的token
     * @return claims 返回荷载部分的键值对
     */
    public Claims decode(String jwtToken) {

        // 得到 DefaultJwtParser
        return Jwts.parser()
                // 设置签名的秘钥
                .setSigningKey(base64EncodedSecretKey)
                // 设置需要解析的 jwt
                .parseClaimsJws(jwtToken)
                .getBody();
    }

    /**
     * 校验 token
     * 在这里可以使用官方的校验,或,
     * 自定义校验规则,例如在 token 中携带密码,进行加密处理后和数据库中的加密密码比较。
     * @param jwtToken 被校验的 jwt Token
     */
    public boolean isVerify(String jwtToken) {
        Algorithm algorithm = null;

        switch (signatureAlgorithm) {
            case HS256:
                algorithm = Algorithm.HMAC256(Base64.decodeBase64(base64EncodedSecretKey));
                break;
            default:
                throw new RuntimeException("不支持该算法");
        }

        JWTVerifier verifier = JWT.require(algorithm).build();
        verifier.verify(jwtToken);  // 校验不通过会抛出异常
        return true;
    }

    public static void main(String[] args) {
        JwtUtil util = new JwtUtil("tom", SignatureAlgorithm.HS256);

        Mapmap = new HashMap<>();
        map.put("username", "tom");
        map.put("password", "123456");
        map.put("age", 20);
        //测试加密生成token
        String jwtToken = util.encode("tom", 30000, map);
        System.out.println(jwtToken);

        //测试token合法性
        util.isVerify(jwtToken);
        System.out.println("合法");

        //测试拿到token之后解密
       util.decode(jwtToken).entrySet().forEach((entry) -> {
            System.out.println(entry.getKey() + ": " + entry.getValue());
       });
    }
}

上述代码我们用main函数进行测试,输出结果如下:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0b20iLCJwYXNzd29yZCI6IjEyMzQ1NiIsImV4cCI6MTYxODkyNjc3NywiaWF0IjoxNjE4OTI2NzQ3LCJhZ2UiOjIwLCJqdGkiOiIyYzkxY2I2OS1lYWEzLTRlMmYtOGViNC1iNDUzM2MxNTE1MjkiLCJ1c2VybmFtZSI6InRvbSJ9.Ws4Vw9Ll60uaFbTGBpZJh-LTMI052l4Zzx81jqKq3qY
合法
sub: tom
password: 123456
exp: 1618926777
iat: 1618926747
age: 20
jti: 2c91cb69-eaa3-4e2f-8eb4-b4533c151529
username: tom

写在最后

以上就是相关jwt的介绍以及传统session实现的对比,接下来,老猫会向大家演示如何通过JWT+shiro实现whale系统的一个登录鉴权功能。关于前端系统的框架,老猫决定使用的是一套网上比较流行的开源框架vue-admin-beautiful,功能相当齐全,也给大家推荐一下这位大神的作品,github地址为: https://github.com/chuzhixin/vue-admin-beautiful,大家可以自行下载试着运行一下。感谢大家持续关注老猫。

标签:开篇,老猫,JWT,用户,认证,token,session,聊聊,whale
来源: https://blog.51cto.com/u_13040551/2727548