springmvc跨域+token验证(app后台框架搭建二)
这是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后台框架搭建二)的更多相关文章
- springmvc跨域+token验证
1)app后台跨域设置 2)拦截器中设置http报文header中token 3)token的生成实现 ==================================== ...
- 整合springboot(app后台框架搭建四)
springboot可以说是为了适用SOA服务出现,一方面,极大的简便了配置,加速了开发速度:第二方面,也是一个嵌入式的web服务,通过jar包运行就是一个web服务: 还有提供了很多metric,i ...
- 自定义统一api返回json格式(app后台框架搭建三)
在统一json自定义格式的方式有多种:1,直接重写@reposeBody的实现,2,自定义一个注解,自己去解析对象成为json字符串进行返回 第一种方式,我就不推荐,想弄得的话,可以自己去研究一下源码 ...
- spring4+springmvc+mybatis基本框架(app后台框架搭建一)
前言: 随着spring 越来越强大,用spring4来搭建框架也是很快速,问题是你是对spring了解有多深入.如果你是新手,那么在搭建的过程中可以遇到各种各样奇葩的问题. SSM框架的搭建是作为我 ...
- spring4+srpingmvc+mybatis基本框架(app后台框架搭建一)
前言: 随着spring 越来越强大,用spring4来搭建框架也是很快速,问题是你是对spring了解有多深入.如果你是新手,那么在搭建的过程中可以遇到各种各样奇葩的问题. SSM框架的搭建是作为我 ...
- SpringMVC跨域问题排查以及源码实现
SpringMVC跨域问题排查以及源码实现 最近一次项目中,将SpringMVC版本从4.1.1升级到4.3.10,出现跨域失败的情况.关于同源策略和跨域解决方案,网上有很多资料. 项目采用的方式是通 ...
- c#关于JWT跨域身份验证解决方案
学习程序,不是记代码,而是学习一种思想,以及对代码的理解和思考. JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案.为了网络应用环境间传递声明而执行的一种基于JSON的开发标准 ...
- JWT跨域身份验证解决方案
JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案.本文介绍JWT的原理和用法. 1. 当前跨域身份验证的问题 Internet服务无法与用户身份验证分开.一般过程如下.1.用户 ...
- SpringMvc跨域支持
SpringMvc跨域支持 在controller层加上注解@CrossOrigin可以实现跨域 该注解有两个参数 1,origins : 允许可访问的域列表 2,maxAge:飞行前响应的缓存持续 ...
随机推荐
- Jmeter测试HTTPS接口
(以支付宝网站为例:https://memberprod.alipay.com/account/reg/index.htm) 浏览器:chrome 一.网页上导出证书 1.点击浏览器小锁--" ...
- 设置MySQL最大连接数
<pre name="code" class="sql">在使用MySQL数据库的时候,经常会遇到这么一个问题,就是"Can not co ...
- javascript-OOP基础详解
前 言 S N 今天给大家详解一下面向对象编程(简称OOP)基础,OOP 语言使我们有能力定义自己的对象和变量类型 .对象拥有属性和方法 . 所以今天就给大家详解对象和类 . 1-1简介 ...
- opencv-python:win7下,搭建python2.7.5环境,配置opencv3.1.0准备开工-OpenCV步步精深
我的个人博客:点这里 搭建python2.7.5环境 下载python2.7.5 64位:https://www.python.org/ftp/python/2.7.5/python-2.7.5.am ...
- 初学者易上手的SSH-struts2 05拦截器与自定义拦截器
因为自己对于struts2也不是很了解,这章将是struts2的最后一章了.那么这一章主要介绍的是拦截器以及怎么样来自定义一个拦截器. struts2的拦截器位于struts2-core(核心包)-& ...
- sqlite3基本相关使用
闲来无事,复习和总结了一下之前学习到的关于sqlite3数据库的相关知识: [1] sqlite3的安装:1.离线安装:sudo dpkg -i *.deb2.在线安装:sudo apt-get in ...
- PHP连接mysql数据库进行增删改查--删除
删除: 1.首页 在foreach里面加入 <td><a href='dele.php?id={$i[0]}'>删除</a></td> 在上面< ...
- 基于Eclipse IDE的Ardupilot飞控源码阅读环境搭建
基于Eclipse IDE的Ardupilot飞控源码阅读环境搭建 作者:Awesome 日期:2017-10-21 需准备的软件工具 Ardupilot飞控源码 PX4 toolchain JAVA ...
- dotweb框架之旅 [四] - 常用对象-HttpContext
dotweb属于一个Web框架,希望通过框架行为,帮助开发人员快速构建Web应用,提升开发效率,减少不必要的代码臃肿. dotweb包含以下几个常用对象: App(dotweb) App容器,为Web ...
- ES6的Iterator遍历器
JS表示集合的对象主要有Array.Set.Object.Map,在以前,遍历它们需要使用2种不同的方法,而现在,JS提出了Iterator机制,可以给不同的数据结构提供统一的遍历方法,就是for…o ...