可以用足球做的游戲視頻網(wǎng)站好的競價賬戶托管外包
目錄
JWT令牌
簡介
JWT生成
解析JWT?
登陸后下發(fā)令牌?
過濾器(Filter)
Filter快速入門?
Filter攔截路徑
過濾器鏈
登錄校驗Filter-流程
攔截器(Interceptor)
Interceptor 快速入門
攔截路徑?
登錄校驗流程?
JWT令牌
簡介
全稱:JSON Web Token(https://iwt.io/)
定義了一種簡潔的、自包含的格式,用于在通信雙方以json數(shù)據(jù)格式安全的傳輸信息。由于數(shù)字簽名的存在,這些信息是可靠的。
組成:
第一部分:Header(頭),記錄令牌類型、簽名算法等。例如:{"alg":"HS256","type":"JWT"}
第二部分:Payload(有效載荷),攜帶一些自定義信息、默認信息等。例如 {"id":"1","username":"Tom"}
第三部分:Signature(簽名),防止Token被篡改、確保安全性。將header、pavload,并加入指定秘鑰,通過指定簽名算法計算而來。
場景:登錄認證,
登錄成功后,生成令牌
后續(xù)每個請求,都要攜帶JWT令牌,系統(tǒng)在每次請求處理之前,先校驗令牌,通過后,再處理?
JWT生成
在pom.xml 導(dǎo)入依賴
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>
測試?
//生成JWT@Testpublic void testGenJwt(){Map<String,Object>claims=new HashMap<>();claims.put("id",1);claims.put("name","Tom");String jwt = Jwts.builder().setClaims(claims)//自定義內(nèi)容.signWith(SignatureAlgorithm.HS256, "itking")//簽名算法.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))//設(shè)置有效期為一個小時.compact();System.out.println(jwt);}
?返回生成的JWT令牌
解析JWT?
@Testpublic void testParseJwt(){Claims claims = Jwts.parser().setSigningKey("itking")//指定簽名密鑰.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVG9tIiwiaWQiOjEsImV4cCI6MTcxODM2ODM3N30.iRwBkPs6CGuUrZpz1YBjh0QubkpEnY6ArxddkVlMclI")//解析令牌.getBody();System.out.println(claims);}
?
JWT校驗時使用的簽名秘鑰,必須和生成IWT令牌時使用的秘鑰是配套的
如果JWT令牌解析校驗時報錯,則說明JWT令牌被篡改或失效了,令牌非法?
登陸后下發(fā)令牌?
令牌生成:登錄成功后,生成JWT令牌,并返回給前端,
令牌校驗:在請求到達服務(wù)端后,對令牌進行統(tǒng)一攔截、校驗?
需要附加一個工具類JwtUtils類
package com.example.Utils;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;public class JwtUtils {private static String signKey = "itking";private static Long expire = 43200000L;/*** 生成JWT令牌* @param claims JWT第二部分負載 payload 中存儲的內(nèi)容* @return*/public static String generateJwt(Map<String, Object> claims){String jwt = Jwts.builder().addClaims(claims).signWith(SignatureAlgorithm.HS256, signKey).setExpiration(new Date(System.currentTimeMillis() + expire)).compact();return jwt;}/*** 解析JWT令牌* @param jwt JWT令牌* @return JWT第二部分負載 payload 中存儲的內(nèi)容*/public static Claims parseJWT(String jwt){Claims claims = Jwts.parser().setSigningKey(signKey).parseClaimsJws(jwt).getBody();return claims;}
}
再更改一下LoginController
package com.example.Controller;import com.example.Pojo.Emp;
import com.example.Pojo.Result;
import com.example.Service.EmpService;
import com.example.Utils.JwtUtils;
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.RestController;import java.util.HashMap;
import java.util.Map;@RestController
public class LoginController {@Autowiredprivate EmpService empService;@PostMapping("/login")public Result login(@RequestBody Emp emp){Emp e= empService.login(emp);//登陸成功,生成令牌,下發(fā)令牌if(e!=null){Map<String, Object> claims=new HashMap<>();claims.put("id",e.getId());claims.put("name",e.getName());claims.put("username",e.getUsername());String jwt = JwtUtils.generateJwt(claims);return Result.success(jwt);}//登陸失敗,返回錯誤信息return Result.error("用戶名或密碼錯誤");}
}
?測試
過濾器(Filter)
概念:Filter 過濾器,是JavaWeb 三大組件(Servlet、Filter、Listener)之一
過濾器可以把對資源的請求攔截下來,從而實現(xiàn)一些特殊的功能。
過濾器一般完成一些通用的操作,比如:登錄校驗、統(tǒng)一編碼處理、敏感字符處理等
Filter快速入門?
定義Filter:定義一個類,實現(xiàn) Filter接口,并重寫其所有方法。
配置Filter: filter類上加 @Webfilter 注解,配置攔截資源的路徑。引導(dǎo)類上加 @ServletComponentScan 開啟Servlet組件支持?
初始化與銷毀已經(jīng)默認實現(xiàn)了
DemoFilter類?
package com.example.Filter;import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;import java.io.IOException;@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {//初始化方法,只調(diào)用一次@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("init初始化方法執(zhí)行了");}//攔截到請求之后調(diào)用,會調(diào)用多次@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("攔截到請求");//放行filterChain.doFilter(servletRequest,servletResponse);}//銷毀方法,只調(diào)用一次@Overridepublic void destroy() {System.out.println("destroy銷毀方法執(zhí)行了");}
}
?還要在啟動類加上@ServletComponentScan
package com.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;@ServletComponentScan//開啟了對servlet組件的支持
@SpringBootApplication
public class TliasWebManagementApplication {public static void main(String[] args) {SpringApplication.run(TliasWebManagementApplication.class, args);}}
放行后訪問對應(yīng)資源,資源訪問完成后,還會回到Filter中嗎?
會
如果回到Filter中,是重新執(zhí)行還是執(zhí)行放行后的邏輯呢?
執(zhí)行放行后邏輯
Filter攔截路徑
Filter 可以根據(jù)需求,配置不同的攔截資源路徑
攔截路徑 | urlPatterns值 | ????????????????????????????????含義 |
攔截具體路徑 | ????????/login | 只有訪問 /login 路徑時,才會被攔截 |
目錄攔截 | ????????/emps/* | 訪問/emps下的所有資源,都會被攔截 |
攔截所有路徑 | ? ? ? ? ? ?/* | 訪問所有資源,都會被攔截 |
過濾器鏈
介紹:一個web應(yīng)用中,可以配置多個過濾器,這多個過濾器就形成了一個過濾器鏈
順序:注解配置的Filter,優(yōu)先級是按照過濾器類名(字符串)的自然排序。
所有的請求,攔截到了之后,都需要校驗令牌嗎?
有一個例外,登錄請求
攔截到請求后,什么情況下才可以放行,執(zhí)行業(yè)務(wù)操作??
有令牌,且令牌校驗通過(合法);否則都返回未登錄錯誤結(jié)果
登錄校驗Filter-流程
- 獲取請求url。
- 判斷請求url中是否包含login,如果包含,說明是登錄操作,放行
- 獲取請求頭中的令牌(token)
- 判斷令牌是否存在,如果不存在,返回錯誤結(jié)果(未登錄)
- 解析token,如果解析失敗,返回錯誤結(jié)果(未登錄)
- 放行。?
package com.example.Filter;import com.alibaba.fastjson.JSONObject;
import com.example.Pojo.Result;
import com.example.Utils.JwtUtils;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;import java.io.IOException;@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest req= (HttpServletRequest) servletRequest;HttpServletResponse resp= (HttpServletResponse) servletResponse;//1獲取請求url。String url=req.getRequestURI().toString();log.info("請求的url:{}",url);//2判斷請求url中是否包含login,如果包含,說明是登錄操作,放行if(url.contains("login")){log.info("登陸操作,放行");filterChain.doFilter(servletRequest,servletResponse);return;}//3獲取請求頭中的令牌(token)String jwt=req.getHeader("token");//4判斷令牌是否存在,如果不存在,返回錯誤結(jié)果(未登錄)if(!StringUtils.hasLength(jwt)){log.info("請求頭token為空,返回未登陸信息");Result error = Result.error("NOT_LOGIN");String notLogin = JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return;}//5解析token,如果解析失敗,返回錯誤結(jié)果(未登錄)try {JwtUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();log.info("解析令牌失敗,返回未登錄信息");Result error = Result.error("NOT_LOGIN");String notLogin = JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return;}//6放行l(wèi)og.info("令牌合法,放行");filterChain.doFilter(servletRequest,servletResponse);}
}
攔截器(Interceptor)
概念:是一種動態(tài)攔截方法調(diào)用的機制,類似于過濾器。Spring框架中提供的,用來動態(tài)攔截控制器方法的執(zhí)行
作用:攔截請求,在指定的方法調(diào)用前后,根據(jù)業(yè)務(wù)需要執(zhí)行預(yù)先設(shè)定的代碼。
Interceptor 快速入門
1.定義攔截器,實現(xiàn)HandlerInterceptor接口,并重寫其所有方法
2.注冊攔截器?
先創(chuàng)建一個包+類
?
然后實現(xiàn)這個接口
再按ctrl+o重寫里面的方法
package com.example.Interceptor;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;@Component
public class LoginCheckInterceptor implements HandlerInterceptor {@Override//目標(biāo)資源方法運行前運行,返回true:放行,放回false,不放行public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle運行了");return true;}@Override//標(biāo)資源方法運行后運行public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle運行了");}@Override//視圖渲染完畢后運行,最后運行public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion運行了");}
}
?再寫個配置類
package com.example.Config;import com.example.Interceptor.LoginCheckInterceptor;
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;@Configuration//配置類
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");}
}
攔截路徑?
攔截路徑 | 含義 | 舉例 |
/* | 一級路徑 | 能匹配/depts,/emps,/login,不能匹配/depts/1 |
/** | 任意級路徑 | 能匹配/depts,/depts/1,/depts/1/2 |
/depts/* | /depts下的一級路徑 | 能匹配/depts/1,不能匹配/depts/1/2,/depts |
/depts/** | /depts下的任意級路徑 | 能匹配/depts,/depts/1,/depts/1/2,不能匹配/emps/1 |
?Filter 與Interceptor
接口規(guī)范不同:過濾器需要實現(xiàn)Filter接口,而攔截器需要實現(xiàn)HandlerInterceptor接口。
攔截范圍不同:過濾器Filter會攔截所有的資源,而Interceptor只會攔截Spring環(huán)境中的資源。
登錄校驗流程?
這個與Filter差不多
package com.example.Interceptor;import com.alibaba.fastjson.JSONObject;
import com.example.Pojo.Result;
import com.example.Utils.JwtUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {@Override//目標(biāo)資源方法運行前運行,返回true:放行,放回false,不放行public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String url=request.getRequestURI().toString();log.info("請求的url:{}",url);//2判斷請求url中是否包含login,如果包含,說明是登錄操作,放行if(url.contains("login")){log.info("登陸操作,放行");return true;}//3獲取請求頭中的令牌(token)String jwt=request.getHeader("token");//4判斷令牌是否存在,如果不存在,返回錯誤結(jié)果(未登錄)if(!StringUtils.hasLength(jwt)){log.info("請求頭token為空,返回未登陸信息");Result error = Result.error("NOT_LOGIN");String notLogin = JSONObject.toJSONString(error);response.getWriter().write(notLogin);return false;}//5解析token,如果解析失敗,返回錯誤結(jié)果(未登錄)try {JwtUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();log.info("解析令牌失敗,返回未登錄信息");Result error = Result.error("NOT_LOGIN");String notLogin = JSONObject.toJSONString(error);response.getWriter().write(notLogin);return false;}//6放行l(wèi)og.info("令牌合法,放行");return true;}@Override//標(biāo)資源方法運行后運行public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle運行了");}@Override//視圖渲染完畢后運行,最后運行public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion運行了");}
}
?努力遇見更好的自己!!!