基于httpServer的web服务器简易搭建+基于jwt的token鉴权 身份验证【java/postman】

关于客户端搭建:【java】基于OkHttpClient实现get和post请求接口/客户端【postman测试wireshark抓包】



token鉴权:

使用用户名和密码去请求,通过算法生成token,但是token不存储在服务器,随后直接把token返回给客户端。一个token分为三个部分,第一部分是Header,第二部分是用户相关信息,第三个部分是签名,相当于一把锁,前两个部分通过HMAC-SHA256算法生成一把钥匙。
需要判断钥匙和锁是否匹配,但是不会直接拿密钥和签名对比,而是重新计算出一个签名(锁),比较两把锁是否相同。数据(Header,用户信息)是一致的,算法也没有变化,结果就不会变,如果数据变化(被篡改)就不会验证通过。

Token和session的区别:
Token其实也是一个字符串,它最大的一个特点就是不会存在服务端,还有一个特点就是不再依赖于cookie的形式,它可以是请求头或者是请求体的方式,也就是Session依赖于cookie,由服务器生成,存储,验证,以cookie的方式存在于客户端,客户端以同样方式发送给服务端,session有状态。

H. 怎么使用token或者session做鉴权做鉴权?
1登陆之后,获取session或者token字符串,将它们携带回客户端。
2请求需要鉴权的接口时,携带对应的session和token。



JWT的身份验证:
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
1、客户端使用用户名跟密码请求登录
2、服务端收到请求,去验证用户名与密码
3、验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
4、客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
5、客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
6、服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

JWT的token组成
实施 Token 验证的方法挺多的,还有一些标准方法,比如 JWT,读作:jot ,表示:JSON Web Tokens 。JWT 标准的 Token 有三个部分:
header(头部)
payload(数据)
signature(签名)
中间用点分隔开,并且都会使用 Base64 编码

头部:
每个 JWT token 里面都有一个 header,也就是头部数据。里面包含了使用的算法,这个 JWT 是不是带签名的或者加密的。主要就是说明一下怎么处理这个 JWT token 。
头部里包含的东西可能会根据 JWT 的类型有所变化,比如一个加密的 JWT 里面要包含使用的加密的算法。唯一在头部里面要包含的是 alg 这个属性,如果是加密的 JWT,这个属性的值就是使用的签名或者解密用的算法。如果是未加密的 JWT,这个属性的值要设置成 none。
算法是 HS256:上面的内容得用 base64url 的形式编码

Payload:
Payload 里面是 Token 的具体内容,这些内容里面有一些是标准字段,你也可以添加其它需要的内容。下面是标准字段:
iss:Issuer,发行者
sub:Subject,主题
aud:Audience,观众
exp:Expiration time,过期时间
nbf:Not before
iat:Issued at,发行时间
jti:JWT ID
另外还有两个自定义的字段,一个是 name ,还有一个是 admin 。

Signature:
JWT 的最后一部分是 Signature ,这部分内容有三个部分,先是用 Base64 编码的 header.payload ,再用加密算法加密一下,加密的时候要放进去一个 Secret ,这个相当于是一个密码,这个密码秘密地存储在服务端。
最后样子如:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXNzd29yZCI6IjEyMyIsImV4cCI6MTY1NTQ1OTI0OSwidXNlcm5hbWUiOiJ6ZGoifQ.zYJWvXg5Oc1-CwRFUXFrfIHtXRAAfOJct39EMh3bAUk





TokenUtil工具类:

public class TokenUtil {

    private static String username = "admin" ;
    private static String password = "123" ;
    //设置30分钟过期
    private static final long EXPIRE_DATE=30*60*1000;
    //token秘钥
    private static final String TOKEN_SECRET = "[自行设置-加密工具串]";

    public static String tokenTest (String username,String password){

        String token = "";
        try {
            //过期时间
            Date date = new Date(System.currentTimeMillis()+EXPIRE_DATE);
            //秘钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            //第一部分:设置头部信息
            Map<String,Object> header = new HashMap<>();
            header.put("typ","JWT");
            header.put("alg","HS256");
            //第二部分:携带username,password信息
            token = JWT.create()
                    .withHeader(header)
                    .withClaim("username",username)
                    .withClaim("password",password).withExpiresAt(date)
                    .sign(algorithm); //第三部分:生成签名
        }catch (Exception e){
            e.printStackTrace();
            return  null;
        }
        return token;
    }
    
	//验证token
    public static boolean verify(String token){
        try {
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); //同样的加密算法
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return  false;
        }
    }



基于HttpServer搭建简易服务器:

.setAuthenticator( new BasicAuthenticator() )实现窗体登陆验证
server.createContext("/", new MyHttpHandler());处理网页/postman请求

public class httpInter {
    static String strClassName = httpInter.class.getName();
    static Logger logger = Logger.getLogger(strClassName);

    public static void main(String[] args) throws IOException {

            HttpServer server = HttpServer.create(new InetSocketAddress(8888), 0);
            //HttpHandler RestDemoHandler = new HttpHandler();
            HttpContext secureContext = server.createContext("/login", new MyHttpHandler());
            String USERNAME="admin";
            String PASSWORD="123";
//              网页登陆窗体,访问:http://localhost:8888/login
                secureContext.setAuthenticator(new BasicAuthenticator("post") {
                    @Override
                    public boolean checkCredentials(String user, String pwd) {
                        if(user.equals(USERNAME) && pwd.equals(PASSWORD)){
                            String token  = TokenUtil.tokenTest(user,pwd);
                            System.out.println(token);
                            System.out.println("login successed.");
                            return true;
                        }
                        else{
                            System.out.println("login failed.");
                            return false;
                        }

                    }
                });

                server.createContext("/test", new MyHttpHandler());
                //设置服务器的线程池对象
                server.setExecutor(Executors.newFixedThreadPool(10));
                System.out.println("[*] Waiting for messages.");
                server.start();

        }
}

这里设置在网页端输入url后:当id和pwd都对了能访问接口,但没有token读不了具体数据。
因为url只能实现get请求,也携带不了对应的headers信息,需要另设插件。
在这里插入图片描述


MyHttpHandler响应处理类:

getRequestParam函数:输入HttpExchange,上半部分处理get请求,下半部分处理post请求

 private String getRequestParam(HttpExchange httpExchange) throws Exception {
        String paramStr = "";

        if (httpExchange.getRequestMethod().equals("GET")) {
            //GET请求读queryString
            Headers h = httpExchange.getRequestHeaders();
            if (h.containsKey("Authorization-Token")) {
                String checkToken = String.join(".", h.get("Authorization-Token"));
                //获取token
                if (TokenUtil.verify(checkToken)){
                    System.out.println("Token Successed");
                    paramStr = httpExchange.getRequestURI().getQuery();
                }else {
                    paramStr="Token Error";
                }
            }
            else {
                paramStr="Token NULL";
            }


        } else {
            //非GET请求读请求体 POST
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpExchange.getRequestBody(), "utf-8"));
            StringBuilder requestBodyContent = new StringBuilder();
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                requestBodyContent.append(line);
            }
            paramStr = requestBodyContent.toString();
            requestBodyContent.append("\r\n");
            // 验证 token
            String USERNAME="admin";
            String PASSWORD="123";
            JSONObject jsonObject = JSONObject.parseObject(paramStr);
            String user=jsonObject.getString("USERNAME");
            String pwd=jsonObject.getString("PASSWORD");
            if(user.equals(USERNAME) && pwd.equals(PASSWORD)){
                System.out.println("login successed.");
                requestBodyContent.append("Token:");
                String token  = TokenUtil.tokenTest(user,pwd);//使用token工具类生成token串
                requestBodyContent.append(token);
            }
            else{
                System.out.println("login failed.");
            }
                paramStr = requestBodyContent.toString();
            }
        return paramStr;
    }

首先客户端利用postman进行测试,通过post请求发送对应的账户密码,获取token在服务器的响应报文中:在这里插入图片描述
然后发送携带token认证信息在headers的get请求:
(这里获取的参数是null是因为上面的服务器里就没有存放任何数据,有兴趣可以自己连一个数据库 此处略过)
在这里插入图片描述


其他处理函数:

public void handle(HttpExchange httpExchange) {
    try {
        StringBuilder responseText = new StringBuilder();
        responseText.append("请求方法:").append(httpExchange.getRequestMethod()).append("<br/>"); //判断get还是post
        responseText.append("请求参数:").append(getRequestParam(httpExchange)).append("<br/>");
        responseText.append("请求头:<br/>").append(getRequestHeader(httpExchange));
        handleResponse(httpExchange, responseText.toString());
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

/**
 * 获取请求头
 */
private String getRequestHeader(HttpExchange httpExchange) {
    Headers headers = httpExchange.getRequestHeaders();
    return headers.entrySet().stream()
            .map((Map.Entry<String, List<String>> entry) -> entry.getKey() + ":" + entry.getValue().toString())
            .collect(Collectors.joining("<br/>"));
}


	/**
     * 处理响应
     */
    private void handleResponse(HttpExchange httpExchange, String responsetext) throws Exception {
        //生成html
        StringBuilder responseContent = new StringBuilder();
        responseContent.append("<html>")
                .append("<body>")
                .append(responsetext)
                .append("</body>")
                .append("</html>");
        String responseContentStr = responseContent.toString();
        byte[] responseContentByte = responseContentStr.getBytes("utf-8");

        //设置响应头,必须在sendResponseHeaders方法之前设置!
        httpExchange.getResponseHeaders().add("Content-Type", "application/json");//text/html;charset=utf-8
        //设置响应码和响应体长度,必须在getResponseBody方法之前调用!
        httpExchange.sendResponseHeaders(200, responseContentByte.length);

        OutputStream out = httpExchange.getResponseBody(); //输出响应报文
        out.write(responseContentByte);
        out.flush();
        out.close();
    }



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Spring Boot、OAuth2.0和JWT Token鉴权认证开发的后台接口是一种使用现代化技术实现的身份验证和授权机制。下面是关于这种后台接口的一些说明: 首先,Spring Boot是一个基于Spring框架的快速开发框架,提供了简化的配置和自动化的特性,使开发者能够更快速高效地开发后台接口。 OAuth2.0是一种开放标准的授权协议,它允许用户授权第三方应用访问他们在资源拥有者上存储的信息,而不需要将用户名和密码提供给第三方。 JWT Token(JSON Web Token)是一种用于在网络应用间安全传递声明的一种方式。它被用作身份验证和授权的令牌,通过加密并以JSON格式存储信息,确保信息的完整性和安全性。 基于以上技术,我们可以开发出具有强大安全认证能力的后台接口。首先,用户在访问接口时,需要提供他们的身份证明,这可以是用户名和密码。接口服务器会使用OAuth2.0协议进行身份验证,并颁发JWT Token给用户。用户在未来的请求,可以使用该Token进行身份验证,而无需每次都提供用户名和密码。 接口服务器会对JWT Token进行验证,以确保Token的完整性和有效性。如果Token失效或被伪造,访问将被拒绝。如果验证通过,接口服务器会正常处理用户的请求。 使用Spring Boot和OAuth2.0进行开发,可以方便地设置权限和角色。可以根据用户的角色和权限,限制他们对某些资源的访问。 总之,基于Spring Boot、OAuth2.0和JWT Token鉴权认证开发的后台接口提供了一种安全可靠的身份验证和授权机制,能够有效保护后台接口的安全性,防止非法访问和数据泄露。这种技术组合在开发现代化的网络应用时非常有用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值