gateway和jwt網(wǎng)關(guān)認(rèn)證實(shí)現(xiàn)過程解析
這篇文章主要介紹了gateway和jwt網(wǎng)關(guān)認(rèn)證實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
思路: 全局過濾器對(duì)所有的請(qǐng)求攔截(生成token有效期30分鐘,放入redis設(shè)置有效期3天。3天之類可以通過刷新接口自動(dòng)刷新,超過3天需要重新登錄。)
前端在調(diào)用接口之前先判斷token是否過期(3o分鐘),過期則先調(diào)刷新接口,換取新token,
1引入相關(guān)jar
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency>
2編寫Jwt工具類(生成token + 解析token)
package spring.cloud.gateway.common; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Map; import io.jsonwebtoken.ExpiredJwtException; import org.springframework.util.StringUtils; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; public class JwtUtil { public static final String SECRET = "qazwsx123444$#%#()*&& asdaswwi1235 ?;!@#kmmmpom in***xx**&"; public static final String TOKEN_PREFIX = "Bearer"; public static final String LOGIN_URL = "/token/userId/pwd"; public static final String LOGOUT_URL = "/token/userId"; public static final String HEADER_AUTH = "authorization"; public static final String HEADER_USERID = "userid"; //token超時(shí)時(shí)間 public static final int TOKEN_EXPIRATION_MINUTE = 30; //token的redis超時(shí)時(shí)間 public static final int TOKEN_REDIS_EXPIRATION_DAY = 7; public static String generateToken(String userId) { Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.MINUTE, TOKEN_EXPIRATION_MINUTE); //得到前一天 Date date = calendar.getTime(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); df.format(date); //todo 優(yōu)化token的生層規(guī)則 HashMap<String, Object> map = new HashMap<>(); map.put(HEADER_USERID, userId); String jwt = Jwts.builder() .setSubject(HEADER_USERID).setClaims(map) .setExpiration(date) .signWith(SignatureAlgorithm.HS512, SECRET) .compact(); return TOKEN_PREFIX + " " + jwt; } public static Map<String, String> validateToken(String token) { HashMap<String, String> tokenMap = new HashMap<String, String>(); if (StringUtils.isEmpty(token)) { return tokenMap; } try { Map<String, Object> tokenBody = Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token.replace(TOKEN_PREFIX, "")) .getBody(); String userId = String.valueOf(tokenBody.get(HEADER_USERID)); tokenMap.put(HEADER_USERID, userId); }catch (ExpiredJwtException e){ e.printStackTrace(); } return tokenMap; } /** * 移到j(luò)wtUtil中去 * * @param token * @return */ public static Map<String, String> validateTokenAndUser(String token, String userIdIn) { Map<String, String> tokenResultMap = new HashMap<>(); if (StringUtils.isEmpty(token) || StringUtils.isEmpty(userIdIn)) { return tokenResultMap; } tokenResultMap = validateToken(token); if (StringUtils.isEmpty(token) || StringUtils.isEmpty(userIdIn)) { return tokenResultMap; } //判斷傳入的userid和token是否匹配 String userIdOri = tokenResultMap.get(HEADER_USERID); if (!userIdIn.equals(userIdOri)) { return new HashMap<String,String>(); } return tokenResultMap; } }
3編寫過濾器類
package spring.cloud.gateway.filter; import java.net.URI; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.cloud.gateway.route.Route; import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.server.PathContainer; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import spring.cloud.gateway.common.JwtUtil; import spring.cloud.gateway.exception.PermissionException; /** * 參數(shù)參考 https://blog.csdn.net/tianyaleixiaowu/article/details/83375246 * response參考 https://bbs.csdn.net/topics/392412604?list=11074255 */ @Component public class AuthFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); HttpHeaders header = request.getHeaders(); HttpMethod method = request.getMethod(); String token = header.getFirst(JwtUtil.HEADER_AUTH); String userId = header.getFirst(JwtUtil.HEADER_USERID); PathContainer pathContainer = request.getPath().pathWithinApplication(); String path = pathContainer.value(); //2- 處理登錄請(qǐng)求 if (StringUtils.isBlank(token)) { //是登錄接口則放行,否則返回異常 if (path.contains(JwtUtil.LOGIN_URL) && HttpMethod.POST.equals(method)) { throw new PermissionException("please login"); } return chain.filter(exchange); } //3- 處理刷新token請(qǐng)求 if (path.indexOf("refresh") >= 0) { //放行去掉刷新接口(在刷新前校驗(yàn)userId和token是否匹配) return chain.filter(exchange); } //4- 處理刷新token請(qǐng)求 if (path.contains(JwtUtil.LOGOUT_URL) && HttpMethod.DELETE.equals(method)) { //放行去掉登出接口(在刷新前校驗(yàn)userId和token是否匹配) return chain.filter(exchange); } //5- 攜帶token請(qǐng)求其他業(yè)務(wù)接口 Map<String, String> validateResultMap = JwtUtil.validateTokenAndUser(token, userId); if (validateResultMap == null || validateResultMap.isEmpty()) { throw new PermissionException("token 已經(jīng)失效"); } // TODO 將用戶信息存放在請(qǐng)求header中傳遞給下游業(yè)務(wù) Route gatewayUrl = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR); URI uri = gatewayUrl.getUri(); //表示下游請(qǐng)求對(duì)應(yīng)的服務(wù)名如 SPRING-CLOUD-SERVICE SPRING-CLOUD-GATEWAY String serviceName = uri.getHost(); ServerHttpRequest.Builder mutate = request.mutate(); mutate.header("x-user-id", validateResultMap.get("userid")); mutate.header("x-user-name", validateResultMap.get("user")); mutate.header("x-user-serviceName", serviceName); ServerHttpRequest buildReuqest = mutate.build(); //todo 如果響應(yīng)中需要放數(shù)據(jù),也可以放在response的header中 //ServerHttpResponse response = exchange.getResponse(); //response.getHeaders().add("new_token","token_value"); return chain.filter(exchange.mutate().request(buildReuqest).build()); } }
4編寫相關(guān)接口API
package spring.cloud.gateway.controller; import org.springframework.web.bind.annotation.*; import spring.cloud.gateway.common.JwtUtil; import java.util.Map; @RestController @RequestMapping("/token") public class TokenController { /** * 登錄接口 * @param user(userID +pwd) * @return */ @PostMapping("/userId/pwd") public String getToken(@RequestBody Map<String,String> user) { //用戶名密碼需要加密處理 String result = ""; if (user == null || user.isEmpty()) { return result; } String userId = user.get("userId"); String pwd = user.get("pwd"); if (!doLogin(userId,pwd)) { return result; } String token = JwtUtil.generateToken(userId); // todo 將token放入redis中,設(shè)置超時(shí)時(shí)間為 2 * t return token; } private Boolean doLogin(String userId,String pwd) { //后續(xù)對(duì)接user表驗(yàn)證 if ("admin".equals(userId) && "123".equals(pwd)) { return true; } if ("spring".equals(userId) && "123".equals(pwd)) { return true; } if ("gateway".equals(userId) && "123".equals(pwd)) { return true; } return false; } /** * 登出接口 */ /** * 刷新token的接口 * 在刷新前校驗(yàn)userId和token是否匹配 */ }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
springmvc實(shí)現(xiàn)json交互-requestBody和responseBody
本文主要介紹了springmvc實(shí)現(xiàn)json交互-requestBody和responseBody的相關(guān)知識(shí)。具有很好的參考價(jià)值。下面跟著小編一起來看下吧2017-03-03JMS簡(jiǎn)介與ActiveMQ實(shí)戰(zhàn)代碼分享
這篇文章主要介紹了JMS簡(jiǎn)介與ActiveMQ實(shí)戰(zhàn)代碼分享,具有一定借鑒價(jià)值,需要的朋友可以參考下2017-12-12Java線上問題排查神器Arthas實(shí)戰(zhàn)原理解析
原先我們Java中我們常用分析問題一般是使用JDK自帶或第三方的分析工具如jstat、jmap、jstack、?jconsole、visualvm、Java?Mission?Control、MAT等,還有一款神器Arthas工具,可幫助程序員解決很多繁瑣的問題,感興趣的朋友一起看看吧2022-01-01Spring Boot使用Redisson實(shí)現(xiàn)滑動(dòng)窗口限流的項(xiàng)目實(shí)踐
滑動(dòng)窗口限流是一種流量控制策略,用于控制在一定時(shí)間內(nèi)的請(qǐng)求頻率,本文主要介紹了Spring Boot使用Redisson實(shí)現(xiàn)滑動(dòng)窗口限流的項(xiàng)目實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03SpringBoot 異步線程間數(shù)據(jù)傳遞的實(shí)現(xiàn)
本文主要介紹了SpringBoot 異步線程間數(shù)據(jù)傳遞的實(shí)現(xiàn),包括異步線程的基本概念、數(shù)據(jù)傳遞的方式、具體實(shí)現(xiàn)方式等,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03