国外 视频上传网站源码,百度站内搜索代码,空调安装工做网站,ftp中如何找到网站首页文章目录 JWT实现单点登录JWT 简介存在问题及解决方案登录流程后端程序实现前端保存Tokenstore存放信息的缺点及解决 校验流程#xff1a;为gateway增加登录校验拦截器 另一种单点登录方法#xff1a;Token#xff0b;Redis实现单点登录 JWT实现单点登录 
登录流程#xff… 文章目录 JWT实现单点登录JWT 简介存在问题及解决方案登录流程后端程序实现前端保存Tokenstore存放信息的缺点及解决 校验流程为gateway增加登录校验拦截器 另一种单点登录方法TokenRedis实现单点登录 JWT实现单点登录 
登录流程 校验用户名密码-生成随机JWT Token-返回给前端。之后前端发请求携带该Token就能验证是哪个用户了。校验流程 从前端请求的header获取JWT Token-根据工具包校验JWT Token-校验成功或失败 
JWT 简介 
结构 Header 头部信息主要声明了JWT的签名算法等信息 Payload 载荷信息主要承载了各种声明并传递明文数据 Signature 签名拥有该部分的JWT被称为JWS也就是签了名的JWT用于校验数据 整体结构是 header.payload.signature 参考文档https://doc.hutool.cn/pages/jwt/ 
存在问题及解决方案 token被解密如工具包被获取。可通过增加“盐值”来解决。  token被拿到第三方使用如被包装到第三方使用ChatGPT工具可以通过限流来解决。  
登录流程 
后端程序实现 
封装hutool工具类 
public class JwtUtil {private static final Logger LOG  LoggerFactory.getLogger(JwtUtil.class);/*** 盐值很重要不能泄漏且每个项目都应该不一样可以放到配置文件中*/private static final String key  xxx;public static String createToken(Long id, String mobile) {LOG.info(开始生成JWT tokenid{}mobile{}, id, mobile);GlobalBouncyCastleProvider.setUseBouncyCastle(false);DateTime now  DateTime.now();DateTime expTime  now.offsetNew(DateField.HOUR, 24);
//        DateTime expTime  now.offsetNew(DateField.SECOND, 10);MapString, Object payload  new HashMap();// 签发时间payload.put(JWTPayload.ISSUED_AT, now);// 过期时间payload.put(JWTPayload.EXPIRES_AT, expTime);// 生效时间payload.put(JWTPayload.NOT_BEFORE, now);// 内容payload.put(id, id);payload.put(mobile, mobile);String token  JWTUtil.createToken(payload, key.getBytes());LOG.info(生成JWT token{}, token);return token;}public static boolean validate(String token) {LOG.info(开始JWT token校验token{}, token);GlobalBouncyCastleProvider.setUseBouncyCastle(false);JWT jwt  JWTUtil.parseToken(token).setKey(key.getBytes());// validate包含了verifyboolean validate  jwt.validate(0);LOG.info(JWT token校验结果{}, validate);return validate;}public static JSONObject getJSONObject(String token) {GlobalBouncyCastleProvider.setUseBouncyCastle(false);JWT jwt  JWTUtil.parseToken(token).setKey(key.getBytes());JSONObject payloads  jwt.getPayloads();payloads.remove(JWTPayload.ISSUED_AT);payloads.remove(JWTPayload.EXPIRES_AT);payloads.remove(JWTPayload.NOT_BEFORE);LOG.info(根据token获取原始内容{}, payloads);return payloads;}public static void main(String[] args) {createToken(1L, 123);String token  eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE3MzY0ODczMDQsIm1vYmlsZSI6IjEyMyIsImlkIjoxLCJleHAiOjE3MzY1NzM3MDQsImlhdCI6MTczNjQ4NzMwNH0.Bui7guCvPEF557eqxRLwmt5tO-W-3oVLnn37H4qOVfA;validate(token);getJSONObject(token);}
}后端定义登录业务 public MemberLoginResp login(MemberLoginReq memberLoginReq){String mobile  memberLoginReq.getMobile();String code  memberLoginReq.getCode();Member memberDB  selectByMobile(mobile);if (ObjectUtil.isEmpty(memberDB)){throw new BusinessException(BusinessExceptionEnum.MEMBER_MOBILE_NOT_EXIST);}if(!code.equals(8888)){throw new BusinessException(BusinessExceptionEnum.MEMBER_MOBILE_CODE_ERROR);}MemberLoginResp memberLoginResp  new MemberLoginResp();memberLoginResp.setId(memberDB.getId());memberLoginResp.setMobile(mobile);String token  JwtUtil.createToken(memberDB.getId(), memberDB.getMobile());memberLoginResp.setToken(token);return memberLoginResp;}通过调用封装的JwtUtil生成token并返回前端 成功返回Token结果 
前端保存Token 
Vuex全局保存Token到store中 
import { createStore } from vuexconst MEMBER  MEMBER;export default createStore({state: {member: {}},getters: {},mutations: {setMember (state, _member) {state.member  _member;}},actions: {},modules: {}
}) const login  ()  {axios.post(/member/member/login, loginForm).then((response)  {let data  response.data;if (data.success) {notification.success({ description: 登录成功 });// 登录成功跳到控台主页router.push(/welcome);store.commit(setMember, data.content);} else {notification.error({ description: data.message });}})};store存放信息的缺点及解决 
store存放用户信息后如果刷新页面那么信息也会消失 store可以理解为缓存一旦重新加载则缓存全都没了。 
解决方法 
step1. 新增session-storage.js封装会话缓存sessionStorage 
// 所有的session key都在这里统一定义可以避免多个功能使用同一个key
SESSION_ORDER  SESSION_ORDER;
SESSION_TICKET_PARAMS  SESSION_TICKET_PARAMS;SessionStorage  {get: function (key) {var v  sessionStorage.getItem(key);if (v  typeof(v) ! undefined  v ! undefined) {return JSON.parse(v);}},set: function (key, data) {sessionStorage.setItem(key, JSON.stringify(data));},remove: function (key) {sessionStorage.removeItem(key);},clearAll: function () {sessionStorage.clear();}
}; 
step2. 在index.html中引入该js 
!DOCTYPE html
html langheadmeta charsetutf-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width,initial-scale1.0link relicon href% BASE_URL %favicon.ico!-- 引入js --script src% BASE_URL %js/session-storage.js/scripttitle% htmlWebpackPlugin.options.title %/title/headbodynoscriptstrongWere sorry but % htmlWebpackPlugin.options.title % doesnt work properly without JavaScript enabled. Please enable it to continue./strong/noscriptdiv idapp/div!-- built files will be auto injected --/body
/htmlstep3. 修改store的index.js 
const MEMBER  MEMBER;export default createStore({state: {member: window.SessionStorage.get(MEMBER) || {} # 读取},getters: {},mutations: {setMember (state, _member) {state.member  _member;window.SessionStorage.set(MEMBER, _member); # 设置}},不再是把member定义为{}而是首先在缓存中获取如果没有则设置为{}。同时避免空指针 同时在用户登录后设置MEMBER缓存 校验流程为gateway增加登录校验拦截器 
添加依赖 dependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion5.8.10/version/dependency拦截器类 
Component
public class LoginMemberFilter implements Ordered, GlobalFilter {private static final Logger LOG  LoggerFactory.getLogger(LoginMemberFilter.class);Overridepublic MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) {String path  exchange.getRequest().getURI().getPath();// 排除不需要拦截的请求if (path.contains(/admin)|| path.contains(/redis)|| path.contains(/test)|| path.contains(/member/member/login)|| path.contains(/member/member/send-code)) {LOG.info(不需要登录验证{}, path);return chain.filter(exchange);} else {LOG.info(需要登录验证{}, path);}// 获取header的token参数String token  exchange.getRequest().getHeaders().getFirst(token);LOG.info(会员登录验证开始token{}, token);if (token  null || token.isEmpty()) {LOG.info( token为空请求被拦截 );exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}// 校验token是否有效包括token是否被改过是否过期boolean validate  JwtUtil.validate(token);if (validate) {LOG.info(token有效放行该请求);return chain.filter(exchange);} else {LOG.warn( token无效请求被拦截 );exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}}/*** 优先级设置  值越小  优先级越高** return*/Overridepublic int getOrder() {return 0;}
}测试结果 
直接调用不需要验证登录的接口 
RestController
public class TestController {GetMapping(/test)public String test(){return test;}}调用需要登录的接口方法未登录  同时服务器端没有打印表示请求已被拦截 调用login登陆后再次执行上述请求 login打印日志  调用请求打印日志  可见成功校验token并读取登录用户信息通过校验 另一种单点登录方法TokenRedis实现单点登录 
登录流程 校验用户名密码-生成随机Token-将Token存放到Redis并返回给前端。 之后前端发请求携带该Token就能验证是哪个用户了。校验流程 从前端请求的header获取Token-根据Token到Redis获取用户数据-若有数据则登录校验通过否则失败