Spring MVC中使用JWT配合登录拦截器

使用登录拦截器+Json Web Token来进行登录验证,后台为SpringMVC (Boot同理)

首先,为我们基于Maven的项目配置依赖:

<dependency>

    <groupId>io.jsonwebtoken</groupId>

    <artifactId>jjwt</artifactId>

    <version>0.7.0</version>

</dependency>

<dependency>

    <groupId>com.auth0</groupId>

    <artifactId>java-jwt</artifactId>

    <version>3.2.0</version>

</dependency>


其次,我们需要一个拦截器,方便我们在其他用户登录时拦截请求并检查token

在DispatcherServlet的配置文件中的<beans>标签内加入拦截器配置声明

<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);});



语言较为仓促,如有不及之处还请多多包涵



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值