在SpringBoot中使用JWT的實(shí)現(xiàn)方法
JWT簡(jiǎn)介
簡(jiǎn)介
JSON Web token簡(jiǎn)稱JWT, 是用于對(duì)應(yīng)用程序上的用戶進(jìn)行身份驗(yàn)證的標(biāo)記。也就是說(shuō), 使用 JWTS 的應(yīng)用程序不再需要保存有關(guān)其用戶的 cookie 或其他session數(shù)據(jù)。此特性便于可伸縮性, 同時(shí)保證應(yīng)用程序的安全。
在身份驗(yàn)證過(guò)程中, 當(dāng)用戶使用其憑據(jù)成功登錄時(shí), 將返回 JSON Web token, 并且必須在本地保存 (通常在本地存儲(chǔ)中)。每當(dāng)用戶要訪問(wèn)受保護(hù)的路由或資源 (端點(diǎn)) 時(shí), 用戶代理(user agent)必須連同請(qǐng)求一起發(fā)送 JWT, 通常在授權(quán)標(biāo)頭中使用Bearer schema。后端服務(wù)器接收到帶有 JWT 的請(qǐng)求時(shí), 首先要做的是驗(yàn)證token。
JWT的格式
JWT就是一個(gè)字符串,經(jīng)過(guò)加密處理與校驗(yàn)處理的字符串,形式為:A.B.C
A由JWT頭部信息header加密得到
B由JWT用到的身份驗(yàn)證信息json數(shù)據(jù)加密得到
C由A和B加密得到,是校驗(yàn)部分
怎樣使用token?
可以放到HTTP請(qǐng)求的請(qǐng)求頭中,通常是Authorization字段。
流程圖

jwt流程圖.png
JWT 實(shí)戰(zhàn)
加入Maven jwt 依賴
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency>
在application.proterties中加入配置
# 加密yan jwt.secret=A0B1C2D3E4F5G6H7I8J9KALBMCNDOEPFQ0R1S2T3U4V5W6X7Y8Z9 # tocken 過(guò)期時(shí)間,單位秒 jwt.expire=300 # 需要認(rèn)證的url,多個(gè)URL使用英文逗號(hào),分割 jwt.authorised-urls=/apis/fis/redis/**
JwtHelper工具類
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.fastjson.JSONObject;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
public class JwtHelper {
private Long EXPIRATION_TIME;
private String SECRET;
private final String TOKEN_PREFIX = "Bearer";
private final String HEADER_STRING = "Authorization";
public JwtHelper(String secret, long expire) {
this.EXPIRATION_TIME = expire;
this.SECRET = secret;
System.out.println("正在初始化Jwthelper,expire="+expire);
}
public JSONObject generateToken(Map<String, Object> claims) {
Calendar c = Calendar.getInstance();
c.setTime(new Date());
c.add(Calendar.SECOND, EXPIRATION_TIME.intValue());
Date d = c.getTime();
String jwt = Jwts.builder()
.setClaims(claims)
.setExpiration(d)
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
JSONObject json = new JSONObject();
json.put("token",TOKEN_PREFIX + " " + jwt);
json.put("token-type", TOKEN_PREFIX);
json.put("expire-time",new SimpleDateFormat("yyyy-MM-dd HH:ss:mm").format(d) );
return json;
}
public Map<String, Object> validateTokenAndGetClaims(HttpServletRequest request) {
String token = request.getHeader(HEADER_STRING);
System.out.println("token is:"+token);
if (token == null) {
return null;
}
Map<String, Object> body = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
.getBody();
return body;
}
}
JWT過(guò)濾器JwtFilter
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.util.AntPathMatcher;
/**
* JWT過(guò)濾器
*
* @author 李慶海
*
*/
public class JwtFilter implements Filter {
private JwtHelper jwtHelper;
private List<String> urls = null;
private static final org.springframework.util.PathMatcher pathMatcher = new AntPathMatcher();
public JwtFilter(JwtHelper jwtHelper, String[] authorisedUrls) {
this.jwtHelper = jwtHelper;
urls = Arrays.asList(authorisedUrls);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, filterConfig.getServletContext());
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.setContentType("application/json; charset=utf-8");
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
if ("OPTIONS".equals(httpRequest.getMethod())) {
httpResponse.setStatus(HttpStatus.NO_CONTENT.value()); // HttpStatus.SC_NO_CONTENT = 204
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with, Token");
httpResponse.setHeader("Access-Control-Allow-Methods", "OPTIONS,GET,POST,DELETE,PUT");
}
String spath = httpRequest.getServletPath();
try {
// 驗(yàn)證受保護(hù)的接口
for (String url : urls) {
if (pathMatcher.match(url, spath)) {
Object token = jwtHelper.validateTokenAndGetClaims(httpRequest);
if (token != null) {
chain.doFilter(request, response);
return;
}else{
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未授權(quán)或者授權(quán)已經(jīng)過(guò)期");
return;
}
}else{
chain.doFilter(request, response);
return;
}
}
} catch (Exception e) {
e.printStackTrace();
}
chain.doFilter(request, response);
return;
}
@Override
public void destroy() {
}
}
配置JWT
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import cn.com.yd.fis.client.jwt.JwtFilter;
import cn.com.yd.fis.client.jwt.JwtHelper;
@Configuration
public class JwtConfig {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expire}")
private long expire;
@Value("${jwt.authorised-urls}")
private String[] authorisedUrls;
@Bean
public JwtHelper jwtHelperBean() {
return new JwtHelper(secret, expire);
}
@Bean
public FilterRegistrationBean basicFilterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
JwtFilter filter = new JwtFilter(jwtHelperBean(), authorisedUrls);
registrationBean.setFilter(filter);
List<String> urlPatterns = new ArrayList<String>();
urlPatterns.add("/*");
registrationBean.setUrlPatterns(urlPatterns);
return registrationBean;
}
}
在Controller中使用JWT
此處僅為說(shuō)明jwt的用法,在實(shí)際應(yīng)用時(shí)可以根據(jù)具體的業(yè)務(wù)需要加入不同的或者更多的參數(shù),一并作為claims進(jìn)行參數(shù)傳遞。
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import cn.com.yd.fis.client.jwt.JwtHelper;
import cn.com.yd.fis.client.util.JsonResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
@RestController
@RequestMapping("${api-url}/auth")
public class AuthorizeController {
@Autowired
private JwtHelper jwtHelper;
@PostMapping("/login")
public Object login(String loginName,String password) throws Exception {
Map<String, Object> claims = new HashMap<String, Object>();
claims.put("loginName", loginName);
if ("1".equals(password)) {
return JsonResult.success(jwtHelper.generateToken(claims));
} else {
return JsonResult.fail("登錄帳號(hào)或者登錄密碼錯(cuò)誤");
}
}
}
輔助工具類JsonResult
import com.alibaba.fastjson.JSONObject;
public class JsonResult {
public static JSONObject success(Object obj) {
JSONObject json = new JSONObject();
json.put("state", true);
json.put("msg", "成功");
if (null != obj) {
json.put("obj", obj);
}
return json;
}
public static JSONObject fail(Object obj) {
JSONObject json = new JSONObject();
json.put("state", false);
json.put("msg", "失敗");
if (null != obj) {
json.put("obj", obj);
}
return json;
}
public static JSONObject toJSONObject(boolean state, String msg, Object obj) {
JSONObject json = new JSONObject();
json.put("state", state);
json.put("msg", msg);
if (null != obj) {
json.put("obj", obj);
}
return json;
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
MybatisPlus BaseMapper 中的方法全部 Invalid bound statement (not f
這篇文章主要介紹了MybatisPlus BaseMapper 中的方法全部 Invalid bound statement (not found)的Error處理方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
Idea設(shè)置全局highlighting?level為Syntax問(wèn)題
這篇文章主要介紹了Idea設(shè)置全局highlighting?level為Syntax問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
我總結(jié)的幾種@Transactional失效原因說(shuō)明
這篇文章主要是我總結(jié)的幾種@Transactional失效原因說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
java中Scanner.next()和Scanner.nextLine的區(qū)別圖文詳解
使用java語(yǔ)言編程,最常用的輸入就是使用Scanner了,它的構(gòu)造很簡(jiǎn)單,這篇文章主要給大家介紹了關(guān)于java中Scanner.next()和Scanner.nextLine區(qū)別的相關(guān)資料,需要的朋友可以參考下2024-02-02
分析Java非阻塞算法Lock-Free的實(shí)現(xiàn)
非阻塞算法一般會(huì)使用CAS來(lái)協(xié)調(diào)線程的操作。雖然非阻塞算法有諸多優(yōu)點(diǎn),但是在實(shí)現(xiàn)上要比基于鎖的算法更加繁瑣和負(fù)責(zé)。本文將會(huì)介紹兩個(gè)是用非阻塞算法實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu)。2021-06-06
SpringBoot自動(dòng)裝配Condition的實(shí)現(xiàn)
Spring4.0新增@Conditional注解,用于條件化Bean的注冊(cè),通過(guò)實(shí)現(xiàn)Condition接口并重寫matches方法,可以控制Bean的創(chuàng)建與否,感興趣的可以了解一下2024-10-10

