springmvc结合jwt的使用,实现前后端分离token验证

1.首先需要导入maven依赖

		
			com.fasterxml.jackson.core
			jackson-core
			2.9.4
		
		
			com.fasterxml.jackson.core
			jackson-databind
			2.9.4
		
		
			com.fasterxml.jackson.core
			jackson-annotations
			2.9.4
		
		
			com.alibaba
			fastjson
			1.2.41
		
		
			io.jsonwebtoken
			jjwt
			0.7.0
		
		
			com.auth0
			java-jwt
			3.2.0
		
		
			org.springframework
			spring-context
			5.1.3.RELEASE
		

		
			org.springframework
			spring-tx
			5.1.3.RELEASE
		

		
			org.quartz-scheduler
			quartz
			2.3.0
		

		
			org.springframework
			spring-context-support
			5.1.3.RELEASE
		
		
			org.springframework
			spring-test
			5.1.3.RELEASE
		

		
			org.springframework
			spring-web
			5.1.3.RELEASE
		
		
			org.springframework
			spring-webmvc
			5.1.3.RELEASE
		
		
			org.slf4j
			slf4j-log4j12
			1.7.16
		

2.编写jwt工具类

package com.dqw.util;

import java.security.Key;
import java.util.Date;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
/**
 * jwt工具类
 * @ClassName:  JWTUtil   
 * @Description:TODO
 * @author: 丁乾文
 * @date:   2019年5月13日 下午7:48:21
 */
public class JWTUtil {
	/**
	 * token加密时使用的密钥
	 * 一旦得到该密钥也就可以伪造token了
	 */
	public static String sercetKey = "InMySchoolOnline";
	/**
	 * 代表token的有效时间
	 */
	public final static long keeptime = 1800000;
	
	/**
	 * JWT由3个部分组成,分别是 头部Header,载荷Payload一般是用户信息和声明,签证Signature一般是密钥和签名
	 * 当头部用base64进行编码后一般都会呈现eyJ...形式,而载荷为非强制使用,签证则包含了哈希算法加密后的数据,包括转码后的header,payload和sercetKey
	 * 而payload又包含几个部分,issuer签发者,subject面向用户,iat签发时间,exp过期时间,aud接收方。
	 * @Title: generToken   
	 * @Description: TODO
	 * @param: @param id 用户id
	 * @param: @param issuer 签发者
	 * @param: @param subject 一般用户名 
	 * @param: @return      
	 * @return: String      
	 * @throws
	 */
	public static String generToken(String id, String issuer, String subject) {
		long ttlMillis = keeptime;
		SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
		//使用Hash256算法进行加密
		long nowMillis = System.currentTimeMillis();
		Date now = new Date(nowMillis);
		//获取系统时间以便设置token有效时间
		byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(sercetKey);
		//将密钥转码为base64形式,再转为字节码
		Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
		//对其使用Hash256进行加密
		JwtBuilder builder = Jwts.builder().setId(id).setIssuedAt(now);
		//JWT生成类,此时设置iat,以及根据传入的id设置token
		if (subject != null) {
			builder.setSubject(subject);
		}
		if (issuer != null) {
			builder.setIssuer(issuer);
		}
		//由于Payload是非必须加入的,所以这时候要加入检测
		builder.signWith(signatureAlgorithm, signingKey);
		//进行签名,生成Signature
		if (ttlMillis >= 0) {
			long expMillis = nowMillis + ttlMillis;
			Date exp = new Date(expMillis);
			builder.setExpiration(exp);
		}
		//返回最终的token结果
		return builder.compact();
	}
	/**
	 * 该函数用于更新token
	 * @Title: updateToken   
	 * @Description: TODO
	 * @param: @param token
	 * @param: @return      
	 * @return: String      
	 * @throws
	 */
	public static String updateToken(String token) {
		//Claims就是包含了我们的Payload信息类
		Claims claims = verifyToken(token);
		String id = claims.getId();
		String subject = claims.getSubject();
		String issuer = claims.getIssuer();
		//生成新的token,根据现在的时间
		return generToken(id, issuer, subject);
	}
	/**
	 * 将token解密出来,将payload信息包装成Claims类返回
	 * @Title: verifyToken   
	 * @Description: TODO
	 * @param: @param token
	 * @param: @return      
	 * @return: Claims      
	 * @throws
	 */
	private static Claims verifyToken(String token) {
		Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(sercetKey))
				.parseClaimsJws(token).getBody();
		return claims;
	}
}

3.编辑token鉴定spring拦截器

package com.dqw.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSON;
import com.dqw.util.JWTUtil;
import com.dqw.util.ResponseData;
/**
 * token鉴定
 * @ClassName:  HeaderTokenInterceptor   
 * @Description:TODO
 * @author: 丁乾文
 * @date:   2019年5月13日 下午8:52:40
 */
public class HeaderTokenInterceptor implements HandlerInterceptor {
	private static final Logger LOG = Logger.getLogger(HeaderTokenInterceptor.class);
	public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
			Object handler) throws Exception {
		ResponseData responseData = null;
		// 获取我们请求头中的token验证字符
		String headerToken = httpServletRequest.getHeader("token");
		// 检测当前页面,我们设置当页面不是登录页面时对其进行拦截
		// 具体方法就是检测URL中有没有login字符串
		if (!httpServletRequest.getRequestURI().contains("login")) {
			if (headerToken == null) {
				// 如果token不存在的话,返回错误信息。
				responseData=ResponseData.customerError();
			}
			try {
				// 对token进行更新与验证
				headerToken = JWTUtil.updateToken(headerToken);
				LOG.debug("token验证通过,并续期了");
			} catch (Exception e) {
				LOG.debug("token验证出现异常!");
				// 当token验证出现异常返回错误信息,token不匹配
				responseData=ResponseData.customerError();
			}
		}
		if(responseData!=null) {//如果有错误信息
			httpServletResponse.getWriter().write(JSON.toJSONString(responseData));
			return false;
		}else {
			// 将token加入返回页面的header
			httpServletResponse.setHeader("token", headerToken);
			return true;
		}
	}
	public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
			ModelAndView modelAndView) throws Exception {
	}
	public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
			Object o, Exception e) throws Exception {
	}
}

4.项目中用到的其他类

package com.dqw.util;

import java.util.HashMap;
import java.util.Map;
/**
 * 响应实体
 * @ClassName:  ResponseData   
 * @Description:TODO
 * @author: 丁乾文
 * @date:   2019年5月13日 下午8:53:10
 */
public class ResponseData {
	private final String message;
    private final int code;
    private final Map data = new HashMap();

    public String getMessage() {
        return message;
    }

    public int getCode() {
        return code;
    }

    public Map getData() {
        return data;
    }

    public ResponseData putDataValue(String key, Object value) {
        data.put(key, value);
        return this;
    }

    private ResponseData(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public static ResponseData ok() {
        return new ResponseData(200, "Ok");
    }

    public static ResponseData notFound() {
        return new ResponseData(404, "Not Found");
    }

    public static ResponseData badRequest() {
        return new ResponseData(400, "Bad Request");
    }

    public static ResponseData forbidden() {
        return new ResponseData(403, "Forbidden");
    }

    public static ResponseData unauthorized() {
        return new ResponseData(401, "unauthorized");
    }

    public static ResponseData serverInternalError() {
        return new ResponseData(500, "Server Internal Error");
    }

    public static ResponseData customerError() {
        return new ResponseData(1001, "customer Error");
    }
}



package com.dqw.po;
/**
 * 用户实体类
 * @ClassName:  User   
 * @Description:TODO
 * @author: 丁乾文
 * @date:   2019年5月13日 下午8:43:38
 */
public class User {
	private Integer id;
	private String email;
	private String password;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}

package com.dqw.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
 * 主要解决请求跨域问题
 * @ClassName:  HttpInterceptor   
 * @Description:TODO
 * @author: 丁乾文
 * @date:   2019年5月13日 下午8:46:41
 */
public class HttpInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 允许跨域
        response.setHeader("Access-Control-Allow-Origin", "*");
        // 允许自定义请求头token(允许head跨域)
        response.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}
package com.dqw.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.dqw.util.ResponseData;
/**
 * 首页
 * @ClassName:  IndexController   
 * @Description:TODO
 * @author: 丁乾文
 * @date:   2019年5月13日 下午9:09:35
 */
@RestController
@RequestMapping("index")
public class IndexController {
	
	@GetMapping("index")
	public ResponseData toLogin() {
		ResponseData responseData = ResponseData.ok();
		return responseData;
	}
}


package com.dqw.controller;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.dqw.po.User;
import com.dqw.util.JWTUtil;
import com.dqw.util.ResponseData;
/**
 * @ClassName:  LoginController   
 * @Description:TODO
 * @author: 丁乾文
 * @date:   2019年5月13日 下午8:41:47
 */
@RestController
@RequestMapping("login")
public class LoginController {
	/**
	 * 用户登录
	 * @Title: login   
	 * @Description: TODO
	 * @param: @param user
	 * @param: @return      
	 * @return: ResponseData      
	 * @throws
	 */
    @PostMapping(value="login")
    public @ResponseBody ResponseData login(User user) {
    	//模拟去查询数据库,看是否存在此用户
    	boolean login = toLogin(user);
    	ResponseData responseData = ResponseData.ok();
    	if(login) {
    		//生成token
    		String token = JWTUtil.generToken("1", "Jersey-Security-Basic", user.getEmail());
    		//向浏览器返回token,客户端受到此token后存入cookie中,或者h5的本地存储中
    		responseData.putDataValue("token", token);
    		//以及用户
    		responseData.putDataValue("user", user);
    	}else {
    		//用户或者密码错误
    		responseData=ResponseData.customerError();
    	}
        return responseData;
    }
    public boolean toLogin(User user) {
    	if(user.getEmail()!=null&&user.getEmail().trim().length()>0) {
    		if(user.getEmail().equals("root")) {
    			if(user.getPassword().equals("123456")) {
    				return true;
    			}
    		}
    	}
    	return false;
    }
}

}


5.附springmvc配置文件

    
    
    
    
    
    	
     	
            
            
         
    	
         
            
            
         
     

6.login.html





Insert title here




	邮箱:
密码:

7.index.html





欢迎




欢迎你(可以从本地存取获取cookie中获取)

 

你可能感兴趣的:(Spring,Mvc)