这是app后台框架搭建的第二课,主要针对app应用是跨域的运用,讲解怎么配置跨域服务;其次讲解怎么进行token验证,通过拦截器设置token验证和把token设置到http报文中。主要有如下:

  1)app后台跨域设置

     2)拦截器中设置http报文header中token

     3)token的生成实现

====================================================================================================

1,app后台跨域的设置

1.1   springmvc4 有直接在请求映射中对跨域的处理,只需加一个@CrossOrign()

    @CrossOrigin(origins = "http://localhost:9000")
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(required=false, defaultValue="World") String name) {
System.out.println("==== in greeting ====");
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}

对全局请求路径的拦截的,则需要在配置类里声明:

  @Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/greeting-javaconfig").allowedOrigins("http://localhost:9000");
}
};
}

“/greeting-javaconfig” 则是你定义的请求路径了,你也可以直接设置为 /api/* 之类的,allowedOrigins也可以匹配成

可以参考官方文档:https://spring.io/guides/gs/rest-service-cors/

1.2 通过filter过滤器进行处理

其实,spring的拦截器也是可以处理跨域的问题,但对于post+json的支持不是很好,用拦截器的支持会好一些:

首先,定义拦截器:

public class CrossFilter extends OncePerRequestFilter {

    @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
// CORS "pre-flight" request
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Access-Control-Max-Age", "1800");//30 min
}
filterChain.doFilter(request, response);
}
}

其次,在web.xml设置过滤:

<filter>
<filter-name>cors</filter-name>
<filter-class>cn.***.filter.CrossFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

当然spring4  appalication.xml 也可以配置成:

<mvc:cors>
<mvc:mapping path="/**" allowed-origins="*" allow-credentials="true" max-age="1800" allowed-methods="GET,POST,OPTIONS"/>
</mvc:cors>

3)我的配置类配置:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.view.InternalResourceViewResolver; import java.util.ArrayList;
import java.util.List; /**
* Created by ThinkPad on 2017/6/15.
*/
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.ouyang.teson"},useDefaultFilters = true)
@PropertySource({"classpath:teson.properties"})
public class WebConfig extends WebMvcConfigurerAdapter{ private final static Logger logger = LoggerFactory.getLogger(WebConfig.class);
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/jsp/function/");
viewResolver.setSuffix(".jsp");
return viewResolver;
} //静态文件
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
logger.info("addResourceHandlers");
registry.addResourceHandler("/static/**").addResourceLocations("/WEB-INF/static/");
} //允许跨域的接口
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/*").allowedOrigins("*")
.allowCredentials(false)
.allowedMethods("GET", "POST", "DELETE", "PUT")
.allowedHeaders("Access-Control-Allow-Origin","Access-Control-Allow-Headers","Access-Control-Allow-Methods"
,"Access-Control-Max-Age")
.exposedHeaders("Access-Control-Allow-Origin")
.maxAge(3600);
} }

2) 在拦截器中设置token

在拦截器中设置token这个比较简单,我就直接带过了,看配置:

  拦截器类:HeaderTokenInterceptor.java

package com.ouyang.teson.intercept;

import com.ouyang.teson.WebConfig;
import com.ouyang.teson.util.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter; /**
* Created by ThinkPad on 2017/6/20.
*/
public class HeaderTokenInterceptor implements HandlerInterceptor { private final static Logger logger = LoggerFactory.getLogger(HeaderTokenInterceptor.class);
@Autowired
JwtUtil jwtUtil;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
// String contentPath=httpServletRequest.getContextPath();
// System.out.println("contenxPath:"+contentPath);
String requestURI=httpServletRequest.getRequestURI();
String tokenStr=httpServletRequest.getParameter("token");
String token="";
if(requestURI.contains("/api/")){
token=httpServletRequest.getHeader("token");
if(token==null && tokenStr==null){
System.out.println("real token:======================is null");
String str="{'errorCode':801,'message':'缺少token,无法验证','data':null}";
dealErrorReturn(httpServletRequest,httpServletResponse,str);
return false;
}
if(tokenStr!=null){
token=tokenStr;
}
token=jwtUtil.updateToken(token);
System.out.println("real token:=============================="+token);
System.out.println("real ohter:=============================="+httpServletRequest.getHeader("Cookie"));
} httpServletResponse.setHeader("token",token);
/* httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
httpServletResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT");*/
return true;
} @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 {
} // 检测到没有token,直接返回不验证
public void dealErrorReturn(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,Object obj){
String json = (String)obj;
PrintWriter writer = null;
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("text/html; charset=utf-8");
try {
writer = httpServletResponse.getWriter();
writer.print(json); } catch (IOException ex) {
logger.error("response error",ex);
} finally {
if (writer != null)
writer.close();
}
} }
httpServletResponse.setHeader("token",token)是设置返回response的header的token信息,每一次拦截的时候,会查看是否有token,如果没有就直接报错
关于app 后台返回的结果,在实际的开发中需要统一返回数据格式,这个会在下一节中讲到。

在webconfig.java 类中添加以下两个方法:

 @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getTokenHeader())
.addPathPatterns("/api/*")
.excludePathPatterns(
"/robots.txt");
} //token 在header的拦截器
@Bean
public HandlerInterceptor getTokenHeader(){
return new HeaderTokenInterceptor();
}

3) token的实现

token的实现使用jwt组件生成token,如果想要自己通过md5,或者rsa加密生成token也比较简便了,只是这个token要缓存起来,每次进行验证,验证完更新token。更新token主要是更新token里包含的时间,防止token过期。如果使用token的话,可以不用存放缓存,对于登陆验证成功后,我们会生成token,这个token还能带有用户的id等基本信息,我们就可以验证他的过期时间,id等信息。

关于jwt 组件的介绍,可以去看看我的 java组件的jwt的介绍。

直接进入主题了:

maven需要导入

<!-- java-web-token 验证授权-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>

jjwt 主要是对jwt进一步封装,可以快速开发web的token认证。

jwt工具类:jwtUtil.java

package com.ouyang.teson.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder; import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date; /**
* Created by ThinkPad on 2017/6/17.
*/
@Component
public class JwtUtil {
public static String sercetKey="mingtianhenganghao";
public final static long keeptime=1800000; /* @Value("${token.sercetKey}")
public static String sercetKey;
@Value("${token.keeptime:30000}")
public static long keeptime;*/ public static String generToken(String id, String issuer, String subject){
long ttlMillis=keeptime;
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(sercetKey);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); JwtBuilder builder = Jwts.builder().setId(id)
.setIssuedAt(now);
if(subject!=null){
builder.setSubject(subject);
}
if(issuer!=null){
builder.setIssuer(issuer);
}
builder .signWith(signatureAlgorithm, signingKey); if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}
return builder.compact();
} public String updateToken(String token){
try {
Claims claims=verifyToken(token);
String id=claims.getId();
String subject=claims.getSubject();
String issuer=claims.getIssuer();
Date date = claims.getExpiration();
return generToken(id, issuer, subject);
}catch (Exception ex){
ex.printStackTrace();
}
return "0";
} public String updateTokenBase64Code(String token) {
BASE64Encoder base64Encoder=new BASE64Encoder();
BASE64Decoder decoder = new BASE64Decoder();
try {
token=new String(decoder.decodeBuffer(token),"utf-8");
Claims claims=verifyToken(token);
String id=claims.getId();
String subject=claims.getSubject();
String issuer=claims.getIssuer();
Date date = claims.getExpiration();
String newToken = generToken(id, issuer, subject);
return base64Encoder.encode(newToken.getBytes());
}catch (Exception ex){
ex.printStackTrace();
}
return "0";
} public static Claims verifyToken(String token){
Claims claims = Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(sercetKey))
.parseClaimsJws(token).getBody();
return claims;
} }

关于拦截器的处理token,及更新token,上面已经给出代码,这里不再列出。来看一下简单的控制类,仅供学习,如果要运用到生产环境还得各种配置和测试。

登陆的控制方法:

@RequestMapping("/login")
public String login(String name,String password, Model model){
if(name==null || password==null){
return "error";
}
String token = jwtUtil.generToken("xiaoming",null,null);
model.addAttribute("token", token);
return "redirect:/api/liu"; }

这里没有做验证,只是简单根据账户密码,生成token后,重定向;接下来的任务就交给拦截器了,拦截器会拦截/api/* 下的请求,然后请求参数有token的会验证token,并更新token,并把token放到header里。

这里可以看到token字符串有两个点,最好把jwt生成的token进行base64位编码,jwtUtil.java里有updateTokenBase64Code(String token)就是处理token进行base64位编码的。处理速度还是蛮快的。

最后,app后台框架的代码会在第五讲左右,把代码放出来。没有那么充足时间,写博客。

springmvc跨域+token验证(app后台框架搭建二)的更多相关文章

  1. springmvc跨域+token验证

      1)app后台跨域设置      2)拦截器中设置http报文header中token      3)token的生成实现 ==================================== ...

  2. 整合springboot(app后台框架搭建四)

    springboot可以说是为了适用SOA服务出现,一方面,极大的简便了配置,加速了开发速度:第二方面,也是一个嵌入式的web服务,通过jar包运行就是一个web服务: 还有提供了很多metric,i ...

  3. 自定义统一api返回json格式(app后台框架搭建三)

    在统一json自定义格式的方式有多种:1,直接重写@reposeBody的实现,2,自定义一个注解,自己去解析对象成为json字符串进行返回 第一种方式,我就不推荐,想弄得的话,可以自己去研究一下源码 ...

  4. spring4+springmvc+mybatis基本框架(app后台框架搭建一)

    前言: 随着spring 越来越强大,用spring4来搭建框架也是很快速,问题是你是对spring了解有多深入.如果你是新手,那么在搭建的过程中可以遇到各种各样奇葩的问题. SSM框架的搭建是作为我 ...

  5. spring4+srpingmvc+mybatis基本框架(app后台框架搭建一)

    前言: 随着spring 越来越强大,用spring4来搭建框架也是很快速,问题是你是对spring了解有多深入.如果你是新手,那么在搭建的过程中可以遇到各种各样奇葩的问题. SSM框架的搭建是作为我 ...

  6. SpringMVC跨域问题排查以及源码实现

    SpringMVC跨域问题排查以及源码实现 最近一次项目中,将SpringMVC版本从4.1.1升级到4.3.10,出现跨域失败的情况.关于同源策略和跨域解决方案,网上有很多资料. 项目采用的方式是通 ...

  7. c#关于JWT跨域身份验证解决方案

    学习程序,不是记代码,而是学习一种思想,以及对代码的理解和思考. JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案.为了网络应用环境间传递声明而执行的一种基于JSON的开发标准 ...

  8. JWT跨域身份验证解决方案

    JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案.本文介绍JWT的原理和用法. 1. 当前跨域身份验证的问题 Internet服务无法与用户身份验证分开.一般过程如下.1.用户 ...

  9. SpringMvc跨域支持

    SpringMvc跨域支持 在controller层加上注解@CrossOrigin可以实现跨域 该注解有两个参数 1,origins  : 允许可访问的域列表 2,maxAge:飞行前响应的缓存持续 ...

随机推荐

  1. vue.js用法和特性详解

      前  言 最近用Vue.js做了一个数据查询平台,还做了一个拼图游戏,突然深深的感到了vue的强大. Vue.js是一套构建用户界面(user interface)的渐进式框架.与其他重量级框架不 ...

  2. IOS系统配置FFMEPG

    在FFMPEG的官网上可以找到标准的配置文档...http://ffmpeg.org/trac/ffmpeg/wiki/MacOSXCompilationGuide 在开始前确保安装了XCODE而且也 ...

  3. TensorFlow问题:The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations.

    1. 问题描述 The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available o ...

  4. win10 uwp 获取按钮鼠标左键按下

    我们可以使用PointerPressed获得鼠标右键按下,但是我们如何获得左键? 其实UWP已经没有MouseLeftButtonDown,于是我们可以使用一个简单方法去获取鼠标左键按下. 我们在xa ...

  5. 原生JS实现淘宝无缝轮播

    <!DOCTYPE html ><html><head><meta http-equiv="Content-Type" content=& ...

  6. 三、Spring的面向切面

    Spring的面向切面 在应用开发中,有很多类似日志.安全和事务管理的功能.这些功能都有一个共同点,那就是很多个对象都需要这些功能.复用这些通用的功能的最简单的方法就是继承或者委托.但是当应用规模达到 ...

  7. 【计算机网络】应用层(一) HTTP

      HTTP报文 HTTP报文是HTTP应用程序间发送的数据块,它由三部分组成:起始行(start line),首部(header)和主体(body),如下图所示:   从分类上,报文又可以分为请求报 ...

  8. (转)[疯狂Java]NIO:Channel的map映射

    原文出自:http://blog.csdn.net/lirx_tech/article/details/51396268 1. 通道映射技术: 1) 其实就是一种快速读写技术,它将通道所连接的数据节点 ...

  9. 基于itchat的微信群聊小助手基础开发(一)

    前段时间由于要管理微信群,基于itchat开发了一个简单的微信机器人 主要功能有: 图灵机器人功能 群聊昵称格式修改提示 消息防撤回功能 斗图功能 要开发一个基于itchat的最基本的聊天机器人,在g ...

  10. 翻译:MLAPP(2.3节 一些常见的离散分布)

    笔者:尝试翻译MLAPP(Machine Learning: a Probabilistic Perspective)一书,供机器学习的学者参考,如有错误理解之处请指出,不胜感激!(如需转载,请联系本 ...