第5次面试:某软国际(2022-03-14)

  这次面试依然没有通过,面试不通过的原因在于两个技术问题,一个是netty,一个是JWT。都到了我的知识盲区了。一个个来吧。

Netty demo

  照着网上的代码,自己写一个demo。首先肯定是添加maven依赖。

        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.75.Final</version>
        </dependency>

  然后再写个服务端处理程序:

package com.youngthing.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.nio.charset.StandardCharsets;

/**
 * 服务handler
 * created at 15/03/2022
 *
 * @author 花书粉丝
 * <a href="mailto://yujianbo@chtwm.com">yujianbo@chtwm.com</a>
 * @since 1.0.0
 */
public class MyServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        final ByteBuf buffer = (ByteBuf) msg;
        System.out.println(buffer.toString(StandardCharsets.UTF_8));
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, world!".getBytes(StandardCharsets.UTF_8)));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}

  再写个main函数:

package com.youngthing.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * 主程序
 * created at 15/03/2022
 *
 * @author 花书粉丝
 * <a href="mailto://yujianbo@chtwm.com">yujianbo@chtwm.com</a>
 * @since 1.0.0
 */
public class Main {
    public static void main(String[] args) {
        // 创建两个线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            final ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new MyServerHandler());
                        }
                    });
            final ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

  但是这写出来的demo,用telnet测试效果并不好,如下图,我敲一个字母就返回一个“Hello, world!”。
在这里插入图片描述

  netty是不难的,但是确实是自己连demo都没写过,所以面挂了。

JWT

  第二个没回答出来的问题是JWT。我根本不知道这是什么东西。那还能怎么办呢?学啊。JWT是Json Web Token的简称。JWT由三部分组成,header、payload、signature。都是json格式再进行base64编码。主要用途就是用于SSO单点登录。客户端将用户名密码提交给服务器用来登录,服务器校验后返回一个JWT。客户端把JWT保存起来,每次请求都发送,服务器则校验JWT,这样就完成了单点登录过程。
  第一部分header解密后,一般是这样的:

{"typ":"JWT","alg":"HS256"}

  第二部分,尽量小,可以是这样只包含id字段的:

{"uid":1}

  第三部分,则是签名,是前两部分先base64编码,再用英文点号拼接,最后再使用算法进行签名。

服务端生成JWT

  服务端生成JWT的代码比较简单,无非是熟练使用java的security包。按照前述的规则,直接写代码就是了:

package com.youngthing.jwt;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.Base64;

/**
 * 生成JWT
 * created at 15/03/2022
 *
 * @author 花书粉丝
 * <a href="mailto://yujianbo@chtwm.com">yujianbo@chtwm.com</a>
 * @since 1.0.0
 */
public class GenerateJwt {

    public static void main(String[] args) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
        String header = "{\"typ\":\"JWT\",\"alg\":\"HS256\"}";
        String payload = "{\"uid\":1}";
        final Base64.Encoder encoder = Base64.getEncoder();
        final String encodedHeader = encoder.encodeToString(header.getBytes(StandardCharsets.UTF_8));
        final String encodedPayload = encoder.encodeToString(payload.getBytes(StandardCharsets.UTF_8));
        final String text = encodedHeader + "." + encodedPayload;
        final Mac instance = Mac.getInstance("HMacSHA256");
        final SecretKey key = KeyGenerator.getInstance("HMacSHA256").generateKey();
        System.out.println(encoder.encodeToString(key.getEncoded()));
        instance.init(key);
        instance.update(text.getBytes(StandardCharsets.UTF_8));
        final byte[] sign = instance.doFinal();
        String signature = encoder.encodeToString(sign);
        System.out.println(encodedHeader + "." + encodedPayload + "." + signature);
    }
}

  输出结果为

qT8cGILvTlunyZ7EdR6osd4EYFSgk3B9clgeBWmih6w=
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjF9.QUnuWLLhIwaYRwLXdS7FDC/9zpHcG3fmz1+Nufna4WI=

服务端验证JWT

  将产生的JWT发送给客户端,客户端则自己要保存起来。然后请求时放在头里提交给服务器。服务器需要验证,这个时候就用普通的方法校验就行了。

package com.youngthing.jwt;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.Base64;

/**
 * 校验JWT
 * created at 15/03/2022
 *
 * @author 花书粉丝
 * <a href="mailto://yujianbo@chtwm.com">yujianbo@chtwm.com</a>
 * @since 1.0.0
 */
public class CheckJwt {

    public static void main(String[] args) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
        String key = "qT8cGILvTlunyZ7EdR6osd4EYFSgk3B9clgeBWmih6w=";
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjF9.QUnuWLLhIwaYRwLXdS7FDC/9zpHcG3fmz1+Nufna4WI=";
        String text = token.substring(0, token.lastIndexOf('.'));
        final Base64.Decoder decoder = Base64.getDecoder();
        final Base64.Encoder encoder = Base64.getEncoder();
        final Mac instance = Mac.getInstance("HMacSHA256");
        instance.init(new SecretKeySpec(decoder.decode(key), "HMacSHA256"));
        instance.update(text.getBytes(StandardCharsets.UTF_8));
        final byte[] sign = instance.doFinal();
        String signature = encoder.encodeToString(sign);
        System.out.println(signature);
        final String clientSignature = token.substring(token.lastIndexOf('.') + 1);
        System.out.println(clientSignature);
        System.out.println(clientSignature.equals(signature));
    }
}

  自此,面试经历整理完毕。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醒过来摸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值