springBoot整合jwt實(shí)現(xiàn)token令牌認(rèn)證的示例代碼
1. 什么token
作為計(jì)算機(jī)術(shù)語時(shí),是“令牌”的意思。Token是服務(wù)端生成的一串字符串,以作客戶端進(jìn)行請(qǐng)求的一個(gè)令牌,當(dāng)?shù)谝淮蔚卿浐?,服?wù)器生成一個(gè)Token便將此Token返回給客戶端,以后客戶端只需帶上這個(gè)Token前來請(qǐng)求數(shù)據(jù)即可,無需再次帶上用戶名和密碼。
使用token機(jī)制的身份驗(yàn)證方法,在服務(wù)器端不需要存儲(chǔ)用戶的登錄記錄。
大概的流程:
1 客戶端使用用戶名和密碼請(qǐng)求登錄。
2 服務(wù)端收到請(qǐng)求,驗(yàn)證用戶名和密碼。
3 驗(yàn)證成功后,服務(wù)端會(huì)生成一個(gè)token,然后把這個(gè)token發(fā)送給客戶端。
4 客戶端收到token后把它存儲(chǔ)起來,可以放在cookie或者Local Storage(本地存儲(chǔ))里。
5 客戶端每次向服務(wù)端發(fā)送請(qǐng)求的時(shí)候都需要帶上服務(wù)端發(fā)給的token。
6 服務(wù)端收到請(qǐng)求,然后去驗(yàn)證客戶端請(qǐng)求里面帶著token,如果驗(yàn)證成功,就向客戶端返回請(qǐng)求的數(shù)據(jù)
2. jwt是什么
實(shí)施 Token 驗(yàn)證的方法挺多的,還有一些標(biāo)準(zhǔn)方法,比如 JWT,讀作:jot ,表示:JSON Web Tokens 。JWT 標(biāo)準(zhǔn)的 Token 有三個(gè)部分:
1. header(頭部),頭部信息主要包括(參數(shù)的類型--JWT,簽名的算法--HS256)
2. poyload(負(fù)荷),負(fù)荷基本就是自己想要存放的信息(因?yàn)樾畔?huì)暴露,不應(yīng)該在載荷里面加入任 何敏感的數(shù)據(jù))
3. sign(簽名),簽名的作用就是為了防止惡意篡改數(shù)據(jù),
例如:中間用點(diǎn)分隔開,并且都會(huì)使用 Base64 編碼,所以真正的 Token 看起來像這樣:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.//頭部 eyJpZCI6IjIiLCJleHAiOjE3MDI0NDE3MDcsInVzZXJuYW1lIjoiYWRtaW4ifQ.//負(fù)載 k8F9h5GQB1-rTVi-8hs9jOWnfpJALSk2Y08xeZb7YlE//簽名
3. jwt的依賴坐標(biāo)
springboot引入jwt:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.1</version>
</dependency>4. springboot整合token
在這里只是給大家一個(gè)演示,
首先要知道如何生成一個(gè)token 那就是上面講到的請(qǐng)求頭+負(fù)載+簽名
package com.hyh.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.hyh.domain.User;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Calendar;
import java.util.Date;
public class JwtUtil {
// 生成token
// Algorithm.HMAC256():使用HS256生成token,密鑰則是用戶的密碼
private static final String SING = "MusicProject";
public String getToken(User user) {
//System.out.println(String.valueOf(user.getId()));
// 設(shè)置token過期時(shí)間
Calendar instance= Calendar.getInstance();
instance.add(Calendar.DATE,7);
String token="";
token= JWT.create()
.withClaim("id",String.valueOf(user.getId())) //設(shè)置載荷
.withClaim("username",user.getUsername())
.withExpiresAt(instance.getTime()) //設(shè)置令牌過期的時(shí)間
.sign(Algorithm.HMAC256(SING));
return token;
}
/**,
* 驗(yàn)證token 合法性
*/
public static DecodedJWT verify(String token) {
return JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
}
}
我把生成token的方法和驗(yàn)證方法弄成了一個(gè)工具類
在這里我定義的簽名是靜態(tài)變量 可以根據(jù)自己需求來定義 這里的id是從數(shù)據(jù)庫里面拿到的 這里的驗(yàn)證token符合的話就放行,否則就拋異常。
接下來就需要配置一個(gè)攔截器 對(duì)于攔截請(qǐng)求資源
public class AuthenticationInterceptor implements HandlerInterceptor {
@Autowired
UserService userService;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
String token = httpServletRequest.getHeader("token");// 從 http 請(qǐng)求頭中取出 token
// 如果不是映射到方法直接通過
if (!(object instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
//檢查有沒有需要用戶權(quán)限的注解
if (method.isAnnotationPresent(TokenRequired.class)) {
TokenRequired userLoginToken = method.getAnnotation(TokenRequired.class);
if (userLoginToken.required()) {
Map<String,Object> map = new HashMap<>();
// 獲取請(qǐng)求頭中令牌
System.out.println(token);
try {
// 驗(yàn)證令牌
JwtUtil.verify(token);
return true; // 放行請(qǐng)求
} catch (SignatureVerificationException e) {
e.printStackTrace();
map.put("msg","無效簽名!");
}catch (TokenExpiredException e){
e.printStackTrace();
map.put("msg","token過期");
}catch (AlgorithmMismatchException e){
e.printStackTrace();
map.put("msg","算法不一致");
}catch (Exception e){
e.printStackTrace();
map.put("msg","token無效!");
}
map.put("state",false); //設(shè)置狀態(tài)
// 將map以json的形式響應(yīng)到前臺(tái) map --> json (jackson)
String json = new ObjectMapper().writeValueAsString(map);
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.getWriter().println(json);
return false;
}
}
return true;
}在這里面 useservice是我自己的實(shí)現(xiàn)類,里面可以查到用戶id
把攔截器注冊(cè):
@Configuration // 配置類
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthenticationInterceptor())
.addPathPatterns("/api/**") // 攔截所有請(qǐng)求
.excludePathPatterns("/api/login","/api/register"); // 放行登錄 注冊(cè)
}
}
這里因?yàn)閿r截了所有請(qǐng)求 但是我們可以自己定義一個(gè)注解來判斷當(dāng)我們請(qǐng)求資源的時(shí)候需不需呀token驗(yàn)證。
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TokenRequired {
boolean required() default true;
}當(dāng)我們?cè)谀硞€(gè)資源上加上了這個(gè)注解 說明這個(gè)資源需要token驗(yàn)證
這是我寫的一個(gè)登錄接口 集成了驗(yàn)證碼功能
/*
* @description: 用戶的登錄
* @param: User user
* @return:result
* @author
* @date: 2023/9/28 10:03
*/
@PostMapping("/login")
public Result login(@RequestBody User user,HttpSession httpSession,HttpServletResponse response){
String checkCode = (String) httpSession.getAttribute("checkCode");
System.out.println(checkCode);
if (user.getCheCode() == null || !user.getCheCode().equalsIgnoreCase(checkCode)) {
return new Result(Code.Err, null, "驗(yàn)證碼錯(cuò)誤");
}
boolean flag = userService.selectUsernamePwd(user);
boolean is_exist = userService.selectByName(user.getUsername());
if (flag) {
JwtUtil jwtUtil = new JwtUtil();
User user1 = userService.selectByNameToken(user.getUsername());
String token = jwtUtil.getToken(user1);
user.setToken(token);
Cookie cookie = new Cookie("username",user.getUsername());
cookie.setMaxAge(60*60*24*7);
cookie.setPath("/");
response.addCookie(cookie);
httpSession.setAttribute("username", user.getUsername());
return new Result(Code.Ok,user,"登錄成功");
}else if(!is_exist){
return new Result(Code.Err,user,"登錄失敗 用戶不存在");
}else{
return new Result(Code.Err,user,"登錄失敗");
}
}這個(gè)資源是需要token驗(yàn)證訪問的資源 加了注解 @TokenRequired
@GetMapping
@TokenRequired
public Result selectAllSingers(HttpServletRequest request) {
List<Singer> singers = songService.selectSingerAll();
Integer code = singers != null ? Code.Ok : Code.Err;
String msg = singers != null ? "" : "數(shù)據(jù)查詢失敗 請(qǐng)重試";
return new Result(code, singers, msg);
}當(dāng)我們沒有token的時(shí)候正常訪問一下:

可以看到是無法訪問的
我們可以先登錄獲取token 在進(jìn)行訪問試一下

因?yàn)槲野裻oken封裝在user里面 所以返回了token 現(xiàn)在把token放到剛剛無法訪問的url的請(qǐng)求頭里,再次訪問一下:

現(xiàn)在訪問有數(shù)據(jù)了 這些數(shù)據(jù)都是我自己封裝好的,你自己可以隨便寫寫字符串返回來進(jìn)行測(cè)試。
到此這篇關(guān)于springBoot整合jwt實(shí)現(xiàn)token令牌認(rèn)證的示例代碼的文章就介紹到這了,更多相關(guān)springBoot token令牌認(rèn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot集成?JWT實(shí)現(xiàn)用戶登錄認(rèn)證的項(xiàng)目實(shí)踐
- SpringBoot結(jié)合JWT實(shí)現(xiàn)用戶登錄、注冊(cè)、鑒權(quán)
- springboot中通過jwt令牌校驗(yàn)及前端token請(qǐng)求頭進(jìn)行登錄攔截實(shí)戰(zhàn)記錄
- SpringBoot整合JWT(JSON?Web?Token)生成token與驗(yàn)證的流程及示例
- SpringSecurity角色權(quán)限控制(SpringBoot+SpringSecurity+JWT)
- Springboot+jwt實(shí)現(xiàn)在線用戶功能(示例代碼)
相關(guān)文章
Springboot hibernate envers使用過程詳解
這篇文章主要介紹了Springboot hibernate envers使用過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
Swagger異常定位紀(jì)實(shí)Swagger設(shè)計(jì)問題分析
這篇文章主要為大家介紹了Swagger異常定位紀(jì)實(shí)Swagger設(shè)計(jì)的問題分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-02-02
SpringBoot整合mybatis結(jié)合pageHelper插件實(shí)現(xiàn)分頁
在本篇文章里小編給大家整理的是關(guān)于SpringBoot整合mybatis使用pageHelper插件進(jìn)行分頁操作相關(guān)知識(shí)點(diǎn),需要的朋友們學(xué)習(xí)下。2020-02-02
Simple Java Mail郵件發(fā)送實(shí)現(xiàn)過程解析
這篇文章主要介紹了Simple Java Mail郵件發(fā)送實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
SpringBoot如何處理@KafkaListener消息
Spring通過KafkaMessageListenerContainer、ConcurrentMessageListenerContainer等組件實(shí)現(xiàn)Kafka消息的監(jiān)聽和處理,并通過@KafkaListener注解將業(yè)務(wù)邏輯與Kafka消費(fèi)者連接起來,Spring?Boot自動(dòng)配置Kafka相關(guān)組件,簡化了Kafka的使用2024-12-12
SpringBoot定時(shí)任務(wù)動(dòng)態(tài)擴(kuò)展ScheduledTaskRegistrar詳解
這篇文章主要為大家介紹了SpringBoot定時(shí)任務(wù)動(dòng)態(tài)擴(kuò)展ScheduledTaskRegistrar類示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
關(guān)于Spring MVC框架中攔截器Interceptor的使用解讀
這篇文章主要介紹了關(guān)于Spring MVC框架中攔截器Interceptor的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
Java學(xué)習(xí)之Lambda表達(dá)式的使用詳解
Lambda表達(dá)式是Java SE 8中一個(gè)重要的新特性,允許通過表達(dá)式來代替功能接口。本文將通過一些簡單的示例和大家講講Lamda表達(dá)式的使用,感興趣的可以了解一下2022-12-12

