使用登录拦截器+Json Web Token来进行登录验证,后台为SpringMVC (Boot同理)
首先,为我们基于Maven的项目配置依赖:
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>0.7.0version>
dependency>
<dependency>
<groupId>com.auth0groupId>
<artifactId>java-jwtartifactId>
<version>3.2.0version>
dependency>
其次,我们需要一个拦截器,方便我们在其他用户登录时拦截请求并检查token
在DispatcherServlet的配置文件中的
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="你的包名.你的拦截器">bean>
mvc:interceptor>
mvc:interceptors>
我们再编写一个拦截器,比如我实现了一个HeaderTokenInterceptor拦截器
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
//实现Spring拦截器接口 HandlerInterceptor
public class HeaderTokenInterceptor implements HandlerInterceptor {
@Autowired
//该注解使Spring自动为bean设置get与set。
JWTUtil jwtUtil;
//JWT工具类
//第一个函数preHandle是预处理函数,比如我们用于拦截登录时,它是第一个工作的。
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
//System.out.println("进入preHandle方法");
String headerToken=httpServletRequest.getHeader("token");
//获取我们请求头中的token验证字符
String tokenStr=httpServletRequest.getParameter("token");
//getParameter的变量是放在我们请求附带的对象中的字符串,例如post方法中附带的account变量等。
if(!httpServletRequest.getRequestURI().contains("login")){
//检测当前页面,我们设置当页面不是登录页面时对其进行拦截
//具体方法就是检测URL中有没有login字符串
if(headerToken==null && tokenStr==null){
httpServletResponse.sendRedirect("login.do");
//如果token不存在的话,我们将页面重定向到login.do,也就是登录页面去。
return false;
//当返回值是false的时候,表示拦截器不会进行处理了,我们调用response来进行响应。
}
if(tokenStr!=null){
headerToken=tokenStr;
//进行token同步,后面我们会对token做验证与更新
}
try {
headerToken=jwtUtil.updateToken(headerToken);
//对token进行更新与验证
}catch(Exception e) {
httpServletResponse.sendRedirect("login.do");
//当token验证出现异常返回到登录页面
return false;
}
System.out.println("real token:=="+headerToken);
System.out.println("real Cookie:=="+httpServletRequest.getHeader("Cookie"));
}
httpServletResponse.setHeader("token",headerToken);
//将token加入返回页面的header
return true;
//当返回true表示第一个阶段结束,随后会执行postHandle和afterCompletion
}
//当请求到达Controller但是未渲染View时进行处理
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 {
}
}
这个拦截器主要的作用就是拦截请求并且检查token
下面我们配置一个JWT类
import java.security.Key;
import java.util.Date;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
@Component
public class JWTUtil {
public static String sercetKey = "InMySchoolOnline";
//token加密时使用的密钥
//一旦得到该密钥也就可以伪造token了
public final static long keeptime = 1800000;
//代表token的有效时间,
//JWT由3个部分组成,分别是 头部Header,载荷Payload一般是用户信息和声明,签证Signature一般是密钥和签名
//当头部用base64进行编码后一般都会呈现eyJ...形式,而载荷为非强制使用,签证则包含了哈希算法加密后的数据,包括转码后的header,payload和sercetKey
//而payload又包含几个部分,issuer签发者,subject面向用户,iat签发时间,exp过期时间,aud接收方。
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);
}
return builder.compact();
//返回最终的token结果
}
//该函数用于更新token
public 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);
}
public static Claims verifyToken(String token) {
Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(sercetKey))
.parseClaimsJws(token).getBody();
//将token解密出来,将payload信息包装成Claims类返回
return claims;
}
}
这样我们就初步实现了一个JWT的拦截->验证过程
然后是运用的过程
业务层:
String token = JWTUtil.generToken("xiaoming",null,null);
利用generToken方法生成一个token,生成的token怎么使用呢?
以Axios为例,
let params = new URLSearchParams();
let token="你生成的token";
params.append("account","登录账号示例");
axios.post('test1.do', params,{headers: {'token': token}}).then(function (response){alert(response.data);});
以上是一个以header中加入token的例子,当然,由于getParameter方法的存在,我们还可以将token加入到params中
let params = new URLSearchParams();
params.append("account","登录账号示例");
params.append("token","你生成的token");
axios.post('test1.do', params).then(function (response){alert(response.data);});
语言较为仓促,如有不及之处还请多多包涵