網頁登錄功能的實現,SpringBoot整合JWT實現登錄認證

 2023-11-07 阅读 70 评论 0

摘要:目錄什么是JWT為什么使用JWTJWT的使用場景JWT的結構JWT的請求流程SpringBoot整合JWT引入依賴編寫配置文件token生成與驗證工具類攔截器攔截token設置攔截規則建立User實體類編寫mapper和xml文件編寫Service層接口以及實現類編寫controller層測試接口測試JWT 網頁登錄功能的實

目錄

    • 什么是JWT
    • 為什么使用JWT
    • JWT的使用場景
    • JWT的結構
    • JWT的請求流程
    • SpringBoot整合JWT
      • 引入依賴
      • 編寫配置文件
      • token生成與驗證工具類
      • 攔截器攔截token
      • 設置攔截規則
      • 建立User實體類
      • 編寫mapper和xml文件
      • 編寫Service層接口以及實現類
      • 編寫controller層測試接口
      • 測試JWT

網頁登錄功能的實現?

什么是JWT

Json web token (JWT), 是為了在網絡應用環境間傳遞聲明而執行的一種基于JSON的開放標準((RFC 7519).該token被設計為緊湊且安全的,特別適用于分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便于從資源服務器獲取資源,也可以增加一些額外的其它業務邏輯所必須的聲明信息,該token也可直接被用于認證,也可被加密。

為什么使用JWT

  • 簡潔(Compact): 可以通過URL,POST參數或者在HTTP header發送,因為數據量小,傳輸速度也很快。
  • 自包含(Self-contained):負載中包含了所有用戶所需要的信息,避免了多次查詢數據庫。
  • 因為Token是以JSON加密的形式保存在客戶端的,所以JWT是跨語言的,原則上任何web形式都支持。
  • 不需要在服務端保存會話信息,特別適用于分布式微服務。

JWT的使用場景

登錄注冊功能實現?身份認證在這種場景下,一旦用戶完成了登陸,在接下來的每個請求中包含JWT,可以用來驗證用戶身份以及對路由,服務和資源的訪問權限進行驗證。由于它的開銷非常小,可以輕松的在不同域名的系統中傳遞,所有目前在單點登錄(SSO)中比較廣泛的使用了該技術。 信息交換在通信的雙方之間使用JWT對數據進行編碼是一種非常安全的方式,由于它的信息是經過簽名的,可以確保發送者發送的信息是沒有經過偽造的。

JWT的結構

  • 頭部(包含令牌的類型與使用的簽名算法)
{"alg": "HS265","typ": "JWT"
}
  • 載荷(有關用戶實體和其他數據的聲明)
{"name": "admin","pass": 123
}
  • 簽證(使用編碼后的header和payload以及一個指定密鑰,然后使用header中指定的算法(HS265)進行簽名.
    簽名的作用是保證JWT沒有被篡改過)

JWT的請求流程

在這里插入圖片描述

SpringBoot整合JWT

引入依賴

<!--引入jwt--><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version></dependency><!--引入mybatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.3</version></dependency><!--引入mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.15</version></dependency> 

編寫配置文件

server.port=8989spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://8.192.12.37:3306/test?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=rootmybatis.type-aliases-package=com.boot.jwt.entity
mybatis.mapper-locations=com/boot/jwt/mapper/*.xmllogging.level.com.baizhi.dao=debug 

token生成與驗證工具類

package com.boot.jwt.config;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.boot.jwt.entity.User;import java.util.Date;/*** @author laz* @date 2022/09/09 14:55*/
public class TokenUtil {//token到期時間60sprivate static final long EXPIRE_TIME= 60*1000;//密鑰鹽private static final String TOKEN_SECRET="123456qwertyuiop789";/*** 創建一個token* @param user* @return*/public static String sign(User user){String token=null;try {Date expireAt=new Date(System.currentTimeMillis()+EXPIRE_TIME);token = JWT.create()//發行人.withIssuer("auth0")//存放數據.withClaim("username",user.getUsername()).withClaim("password",user.getPassword())//過期時間.withExpiresAt(expireAt).sign(Algorithm.HMAC256(TOKEN_SECRET));} catch (IllegalArgumentException|JWTCreationException je) {}return token;}/*** 對token進行驗證* @param token* @return*/public static Boolean verify(String token){try {//創建token驗證器JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();DecodedJWT decodedJWT=jwtVerifier.verify(token);System.out.println("認證通過:");System.out.println("username: " + TokenUtil.getUserName(token));System.out.println("過期時間:    " + decodedJWT.getExpiresAt());} catch (IllegalArgumentException |JWTVerificationException e) {//拋出錯誤即為驗證不通過return false;}return true;}/*** 獲取用戶名*/public static String getUserName(String token){try{DecodedJWT jwt=JWT.decode(token);return  jwt.getClaim("username").asString();}catch (JWTDecodeException e){return null;}}
}

攔截器攔截token

package com.boot.jwt.config;import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** @author laz* @date 2022/09/09 14:56*/
@Component
public class TokenInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//跨域請求會首先發一個option請求,直接返回正常狀態并通過攔截器if(request.getMethod().equals("OPTIONS")){response.setStatus(HttpServletResponse.SC_OK);return true;}//獲取到tokenString token = request.getHeader("token");if (token!=null){boolean result= TokenUtil.verify(token);if (result){System.out.println("通過攔截器");return true;}}try {JSONObject json=new JSONObject();json.put("msg","token verify fail");json.put("code","500");response.getWriter().append(json.toString());System.out.println("認證失敗,未通過攔截器");} catch (Exception e) {return false;}return false;}}

設置攔截規則

package com.boot.jwt.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.ArrayList;
import java.util.List;/*** @author laz* @date 2022/09/09 13:56*/
@Configuration
public class WebConfiguration implements WebMvcConfigurer {@Autowiredprivate TokenInterceptor tokenInterceptor;/*** 配置攔截器、攔截路徑* 每次請求到攔截的路徑,就會去執行攔截器中的方法* @param*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {List<String> excludePath = new ArrayList<>();//排除攔截,除了登錄,其他都攔截excludePath.add("/test/login");registry.addInterceptor(tokenInterceptor).addPathPatterns("/**").excludePathPatterns(excludePath);WebMvcConfigurer.super.addInterceptors(registry);}}

建立User實體類

package com.boot.jwt.entity;import lombok.Data;/*** @author laz* @date 2022/09/09 14:54*/
@Data
public class User {private String id;private String username;private String password;
}

編寫mapper和xml文件

package com.boot.jwt.mapper;import com.boot.jwt.entity.User;/*** @author laz* @date 2022/09/09 14:54*/
public interface UserMapper {/*** 登錄* @param user* @return*/User login(User user);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.boot.jwt.mapper.UserMapper"><select id="login" parameterType="com.boot.jwt.entity.User" resultType="com.boot.jwt.entity.User">select * from user where username=#{username} and password = #{password}</select></mapper> 

編寫Service層接口以及實現類

package com.boot.jwt.service;import com.boot.jwt.entity.User;
import com.boot.jwt.utils.LoginDto;/*** @author laz* @date 2022/09/09 14:54*/
public interface IUserService {/*** 登錄接口* @param user* @return*/LoginDto login(User user);}
package com.boot.jwt.service.impl;import com.boot.jwt.config.TokenUtil;
import com.boot.jwt.entity.User;
import com.boot.jwt.mapper.UserMapper;
import com.boot.jwt.service.IUserService;
import com.boot.jwt.utils.LoginDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** @author laz* @date 2022/09/09 14:54*/
@Service
public class IUserServiceImpl implements IUserService {@Autowiredprivate UserMapper userMapper;@Overridepublic LoginDto login(User user) {LoginDto loginDto = new LoginDto();User login = userMapper.login(user);if (login == null){loginDto.setCode(400);loginDto.setMsg("賬號或密碼錯誤!");return loginDto;}String token= TokenUtil.sign(login);loginDto.setCode(200);loginDto.setMsg("登錄成功!");loginDto.setUser(login);loginDto.setToken(token);return loginDto;}
}

編寫controller層測試接口

package com.boot.jwt.controller;import com.boot.jwt.entity.User;
import com.boot.jwt.service.IUserService;
import com.boot.jwt.utils.LoginDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author laz* @date 2022/09/09 14:58*/
@RestController
@RequestMapping("/test")
public class LoginController {@Autowiredprivate IUserService userService;/*** 登錄* @param user* @return*/@PostMapping("/login")public LoginDto login(@RequestBody User user){LoginDto login = userService.login(user);return login;}/*** 測試* @return*/@RequestMapping("/test")public Object test(){return "訪問成功!";}}

到這里,代碼就編寫完成了,下面開始測試。

測試JWT

先調用測試接口
在這里插入圖片描述
可以看到,接口被攔截了。

接下來調用login接口,獲取token:
在這里插入圖片描述
再次調用測試接口,帶上token:
在這里插入圖片描述
可以看到,接口成功訪問。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/169412.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息