详解使用JWT实现单点登录(完全跨域方案)(4)

/** * @Author: Helon * @Description: JWT使用常量值 * @Data: Created in 2018/7/27 14:37 * @Modified By: */ public class SecretConstant { //签名秘钥 自定义 public static final String BASE64SECRET = "***********"; //超时毫秒数(默认30分钟) public static final int EXPIRESSECOND = 1800000; //用于JWT加密的密匙 自定义 public static final String DATAKEY = "************"; }

客户端pom依赖:

<!--jwt工具类--> <dependency> <groupId>com.chtwm.component</groupId> <artifactId>jwt-helper</artifactId> <version>xxx</version> </dependency>

客户端拦截器:

/** * @Author: Helon * @Description: 校验是否登录拦截器 * @Data: Created in 2018/7/30 14:30 * @Modified By: */ @Slf4j public class ValidateLoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { //首先从请求头中获取jwt串,与页面约定好存放jwt值的请求头属性名为User-Token String jwt = httpServletRequest.getHeader("User-Token"); log.info("[登录校验拦截器]-从header中获取的jwt为:{}", jwt); //判断jwt是否有效 if(StringUtils.isNotBlank(jwt)){ //校验jwt是否有效,有效则返回json信息,无效则返回空 String retJson = JwtHelper.validateLogin(jwt); log.info("[登录校验拦截器]-校验JWT有效性返回结果:{}", retJson); //retJSON为空则说明jwt超时或非法 if(StringUtils.isNotBlank(retJson)){ JSONObject jsonObject = JSONObject.parseObject(retJson); //校验客户端信息 String userAgent = httpServletRequest.getHeader("User-Agent"); if (userAgent.equals(jsonObject.getString("userAgent"))) { //获取刷新后的jwt值,设置到响应头中 httpServletResponse.setHeader("User-Token", jsonObject.getString("freshToken")); //将客户编号设置到session中 httpServletRequest.getSession().setAttribute(GlobalConstant.SESSION_CUSTOMER_NO_KEY, jsonObject.getString("userId")); return true; }else{ log.warn("[登录校验拦截器]-客户端浏览器信息与JWT中存的浏览器信息不一致,重新登录。当前浏览器信息:{}", userAgent); } }else { log.warn("[登录校验拦截器]-JWT非法或已超时,重新登录"); } } //输出响应流 JSONObject jsonObject = new JSONObject(); jsonObject.put("hmac", ""); jsonObject.put("status", ""); jsonObject.put("code", "4007"); jsonObject.put("msg", "未登录"); jsonObject.put("data", ""); httpServletResponse.setCharacterEncoding("UTF-8"); httpServletResponse.setContentType("application/json; charset=utf-8"); httpServletResponse.getOutputStream().write(jsonObject.toJSONString().getBytes("UTF-8")); return false; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }

客户端拦截器在XML文件中配置:

<!--拦截器配置--> <mvc:interceptors> <mvc:interceptor> <!--需拦截url配置--> <mvc:exclude-mapping path="/api/aa/bb/**" /> <mvc:exclude-mapping path="/api/aa/cc/test" /> <bean /> </mvc:interceptor> </mvc:interceptors>

到此,后台服务的配置已经完成,下一步就需要前端页面将JWT令牌从response响应头中取出,然后存入localstorage或cookie中。但是遇到跨域场景,处理起来就会比较复杂,因为一旦在浏览器中跨域将获取不到localstorage中的JWT令牌。例如域下的JWT,在域下是获取不到的,所以我选择了一种页面跨域的方式进行处理,使用iframe+H5的postMessage(参考博文),具体我使用代码分享的方式来分析。

前端页面js代码(服务端):

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/d6fb65bb6e0438668e536e9991895d09.html