java基于token验证之登陆验证

转载地址:https://blog.csdn.net/kkkun_joe/article/details/81878231

以上博主讲的更清除些,此博客是为了自己加深记忆。

对于前后端分离的项目来说session来判断是否登陆实现比较困难,token是比较好的方式。

大概流程:

 1.用户登陆,若成功则后台生成一个token,并把此token返回给客户端浏览器

2.客户端接收到token后,每次请求都要把此token放到header中发给后段

3.后段使用拦截器判断token的正确性和实效性。

以下是具体代码:

Token工具类:

package com.sign;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class TokenSign {

    /**
     * 过期时间60分钟
     */
    private static final long EXPIRE_TIME=60 * 60 *1000;

    /**
     * 私钥,使用它生成token,最好进行下加密
     */
    private static final String TOKEN_SECRET="Token";


    /**
     * 产生token
     * @param useName
     * @param userId
     * @return
     */
    public static String sign(String useName,String userId){

        try{

            //设置15分钟失效
            Date date=new Date(System.currentTimeMillis()+EXPIRE_TIME);
            //私钥及加密算法
            Algorithm algorithm=Algorithm.HMAC256(TOKEN_SECRET);
            //设置头部信息
            Map<String,Object> header=new HashMap<>();
            header.put("typ","JWT");
            header.put("alg","HS256");
            //附带username和userid信息,存储到token中,生成签名
            return JWT.create()
                    .withHeader(header)
                    //存储自己想要留存给客户端浏览器的内容
                    .withClaim("userName",useName)
                    .withClaim("userId",userId)
                    .withExpiresAt(date)
                    .sign(algorithm);



        }catch (Exception e){
            e.printStackTrace();
        }

        return null;
    }


    /**
     * token校验是否正确
     * @param token
     * @return
     */

    public static boolean verify(String token){

        try {
            Algorithm algorithm=Algorithm.HMAC256(TOKEN_SECRET);

            JWTVerifier verifier =JWT.require(algorithm).build();
            //此方法若token验证失败会抛错的,所以直接return true没问题
            DecodedJWT decodedJWT =verifier.verify(token);
            return true;
        }catch (Exception e){
            e.printStackTrace();
        }

        return false;
    }


    /**
     * 获取token中信息 userName
     * @param token
     * @return
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userName").asString();
        } catch (JWTDecodeException e) {
            e.getStackTrace();
        }
        return null;
    }


    /**
     * 获取token中信息 userId
     * @param token
     * @return
     */
    public static String getUserId(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userId").asString();
        } catch (JWTDecodeException e) {
            e.getStackTrace();

        }
        return null;
    }


}

拦截器:

package com.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.constant.TokenConstant;
import com.sign.TokenSign;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;


@Component
public class LoginInterceptor implements HandlerInterceptor {


    //    在请求处理之前调用,只有返回true才会执行要执行的请求
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {

        httpServletResponse.setCharacterEncoding("UTF-8");
        String token=httpServletRequest.getHeader("accessToken");
        if (null==token){
            Map<String,Object> map=new HashMap<>();
            map.put("data","token is null");
            map.put("code","401");
            httpServletResponse.getWriter().write(JSONObject.toJSONString(map));
            return false;
        }else {
            boolean result= TokenSign.verify(token);

            if (result){
                //更新存储的token信息
                TokenConstant.updateTokenMap(token);
                return true;
            }

            Map<String,Object> map=new HashMap<>();
            map.put("data","token is null");
            map.put("code","401");
            httpServletResponse.getWriter().write(JSONObject.toJSONString(map));
            return false;

        }


    }

    //    试图渲染之后执行
    @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 {

    }


}
package com.constant;

import java.util.HashMap;
import java.util.Map;

public class TokenConstant {

    private static Map<String,String> map=new HashMap();


    public static String getToken(){
            return map.get("token");
    }

    public static void updateTokenMap(String token){
        map.put("token",token);
    }


}

注册拦截器:

package com.adapter;

import com.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Configuration
public class LoginAdapter implements WebMvcConfigurer {


    //解决跨域问题
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedHeaders("Content-Type","X-Requested-With","accept,Origin","Access-Control-Request-Method","Access-Control-Request-Headers","token")
                .allowedMethods("*")
                .allowedOrigins("*")
//是否允许使用cookie
                .allowCredentials(true);
    }




    @Autowired
    private LoginInterceptor loginInterceptor;


    // 这个方法是用来配置静态资源的,比如html,js,css,等等
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    }



    // 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        System.out.println("进入拦截器");
        //addPathPatterns是表明拦截哪些请求
        //excludePathPatterns是对哪些请求不做拦截
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/user/login");
    }

}

以上是后台的配置,除了登陆所有请求都会进行token验证。

前端代码概要:

前端用的VUE

<template>
  <div class="login">
    <!--打包时用这个-->
    <div class="welcome"><img src="/dist/static/image/welcome.png"></div>
    <!--本地用这个-->
    <!--<div class="welcome"><img src="/static/image/welcome.png"></div>-->
    <div class="login-form">
      <div class="login-inp"><label>账号</label><input type="text"  placeholder="请输入账号" v-model="user.account"></div>
      <div class="login-inp"><label>密码</label><input type="password" placeholder="请输入密码" v-model="user.password"></div>

      <div class="login-inp" v-show="!loadingShow" v-on:click="ok()">
        <input type="button" value="立即登录" />
      </div>
    </div>
<!--加载效果-->
    <wv-loadmore v-show="this.loadingShow"></wv-loadmore>


  </div>
</template>

<script>
import Vue from 'vue';
import Axios from 'axios'
import { Toast } from 'we-vue'
export default {
  name: 'Login',
  data: function () {
    return {
      user: {account: '', password: ''},
      show: false,
      url:this.GLOBAL.loginUrl,
      isDisable:false,
      loadingShow:false
    }
  },
  methods: {
    ok: function () {
      if (!this.user.account || !this.user.password) {
        // Toast.loading('加载中');
        Toast.text('请完善登陆信息');
        console.log('param not allow null')
        return
      };

      this.isDisable=true;
      this.loadingShow=true;




      setTimeout(() => {

        Axios.post(this.url,
          this.user,
          {  //方式2通过transformRequest方法发送数据,本质还是将数据拼接成字符串
            transformRequest:[
              function(data){
                let params='';
                for(let index in data){
                  params+=index+'='+data[index]+'&';
                }
                return params;
              }
            ]
          })
          .then(response => {
            if (response.data) {
              //存储token
              localStorage.setItem('accessToken', response.data);
              this.$router.push({ path: 'home' })
            }else {
              Toast.fail('登陆失败');
              console.log('登陆失败:', response.data.message)
            }
            this.loadingShow=false;
            this.isDisable=false;
          })
          .catch(error => {
            Toast.fail('请求失败');
            console.log('请求失败:', error)
            this.loadingShow=false;
            this.isDisable=false;
          })

      }, 1000)






    },
    cancel: function () {
      this.show = false
      this.$emit('cancel', this.flowParam)
    }

}
}

</script>

登陆界面最主要的是:localStorage.setItem('accessToken', response.data);把token信息存储

每次请求都放到header中:

此处简写:

Axios.post(this.addUrl,param,
          {headers: {'Content-Type':'application/json;charset=UTF-8','accessToken':localStorage.getItem('accessToken')}},
          {method: 'put'}
        ).then(response => {

localStorage.getItem('accessToken');获取存储在localStorage中的token信息

  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值