java基于token验证之登陆验证

Posted earlybridvic

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java基于token验证之登陆验证相关的知识,希望对你有一定的参考价值。

转自博客 https://blog.csdn.net/weixin_39102174/article/details/90411116

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

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

大概流程:

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

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

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

以下是具体代码:

Token工具类: 

  1. package com.sign;
  2.  import com.auth0.jwt.JWT;
  3.  
    import com.auth0.jwt.JWTVerifier;
  4.  
    import com.auth0.jwt.algorithms.Algorithm;
  5.  
    import com.auth0.jwt.exceptions.JWTDecodeException;
  6.  
    import com.auth0.jwt.interfaces.DecodedJWT;
  7.  
     
  8.  
    import java.util.Date;
  9.  
    import java.util.HashMap;
  10.  
    import java.util.Map;
  11.  
     
  12.  
    public class TokenSign {
  13.  
     
  14.  
    /**
  15.  
    * 过期时间60分钟
  16.  
    */
  17.  
    private static final long EXPIRE_TIME=60 * 60 *1000;
  18.  
     
  19.  
    /**
  20.  
    * 私钥,使用它生成token,最好进行下加密
  21.  
    */
  22.  
    private static final String TOKEN_SECRET="Token";
  23.  
     
  24.  
     
  25.  
    /**
  26.  
    * 产生token
  27.  
    * @param useName
  28.  
    * @param userId
  29.  
    * @return
  30.  
    */
  31.  
    public static String sign(String useName,String userId){
  32.  
     
  33.  
    try{
  34.  
     
  35.  
    //设置15分钟失效
  36.  
    Date date=new Date(System.currentTimeMillis()+EXPIRE_TIME);
  37.  
    //私钥及加密算法
  38.  
    Algorithm algorithm=Algorithm.HMAC256(TOKEN_SECRET);
  39.  
    //设置头部信息
  40.  
    Map<String,Object> header=new HashMap<>();
  41.  
    header.put("typ","JWT");
  42.  
    header.put("alg","HS256");
  43.  
    //附带username和userid信息,存储到token中,生成签名
  44.  
    return JWT.create()
  45.  
    .withHeader(header)
  46.  
    //存储自己想要留存给客户端浏览器的内容
  47.  
    .withClaim("userName",useName)
  48.  
    .withClaim("userId",userId)
  49.  
    .withExpiresAt(date)
  50.  
    .sign(algorithm);
  51.  
     
  52.  
     
  53.  
     
  54.  
    }catch (Exception e){
  55.  
    e.printStackTrace();
  56.  
    }
  57.  
     
  58.  
    return null;
  59.  
    }
  60.  
     
  61.  
     
  62.  
    /**
  63.  
    * token校验是否正确
  64.  
    * @param token
  65.  
    * @return
  66.  
    */
  67.  
     
  68.  
    public static boolean verify(String token){
  69.  
     
  70.  
    try {
  71.  
    Algorithm algorithm=Algorithm.HMAC256(TOKEN_SECRET);
  72.  
     
  73.  
    JWTVerifier verifier =JWT.require(algorithm).build();
  74.  
    //此方法若token验证失败会抛错的,所以直接return true没问题
  75.  
    DecodedJWT decodedJWT =verifier.verify(token);
  76.  
    return true;
  77.  
    }catch (Exception e){
  78.  
    e.printStackTrace();
  79.  
    }
  80.  
     
  81.  
    return false;
  82.  
    }
  83.  
     
  84.  
     
  85.  
    /**
  86.  
    * 获取token中信息 userName
  87.  
    * @param token
  88.  
    * @return
  89.  
    */
  90.  
    public static String getUsername(String token) {
  91.  
    try {
  92.  
    DecodedJWT jwt = JWT.decode(token);
  93.  
    return jwt.getClaim("userName").asString();
  94.  
    } catch (JWTDecodeException e) {
  95.  
    e.getStackTrace();
  96.  
    }
  97.  
    return null;
  98.  
    }
  99.  
     
  100.  
     
  101.  
    /**
  102.  
    * 获取token中信息 userId
  103.  
    * @param token
  104.  
    * @return
  105.  
    */
  106.  
    public static String getUserId(String token) {
  107.  
    try {
  108.  
    DecodedJWT jwt = JWT.decode(token);
  109.  
    return jwt.getClaim("userId").asString();
  110.  
    } catch (JWTDecodeException e) {
  111.  
    e.getStackTrace();
  112.  
     
  113.  
    }
  114.  
    return null;
  115.  
    }
  116.  
     
  117.  
     
  118.  
    }

拦截器:

  1.  
    package com.interceptor;
  2.  
     
  3.  
    import com.alibaba.fastjson.JSONObject;
  4.  
    import com.constant.TokenConstant;
  5.  
    import com.sign.TokenSign;
  6.  
    import org.springframework.stereotype.Component;
  7.  
    import org.springframework.web.servlet.HandlerInterceptor;
  8.  
    import org.springframework.web.servlet.ModelAndView;
  9.  
     
  10.  
    import javax.servlet.http.HttpServletRequest;
  11.  
    import javax.servlet.http.HttpServletResponse;
  12.  
    import java.util.HashMap;
  13.  
    import java.util.Map;
  14.  
     
  15.  
     
  16.  
    @Component
  17.  
    public class LoginInterceptor implements HandlerInterceptor {
  18.  
     
  19.  
     
  20.  
    // 在请求处理之前调用,只有返回true才会执行要执行的请求
  21.  
    @Override
  22.  
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
  23.  
     
  24.  
    httpServletResponse.setCharacterEncoding("UTF-8");
  25.  
    String token=httpServletRequest.getHeader("accessToken");
  26.  
    if (null==token){
  27.  
    Map<String,Object> map=new HashMap<>();
  28.  
    map.put("data","token is null");
  29.  
    map.put("code","401");
  30.  
    httpServletResponse.getWriter().write(JSONObject.toJSONString(map));
  31.  
    return false;
  32.  
    }else {
  33.  
    boolean result= TokenSign.verify(token);
  34.  
     
  35.  
    if (result){
  36.  
    //更新存储的token信息
  37.  
    TokenConstant.updateTokenMap(token);
  38.  
    return true;
  39.  
    }
  40.  
     
  41.  
    Map<String,Object> map=new HashMap<>();
  42.  
    map.put("data","token is null");
  43.  
    map.put("code","401");
  44.  
    httpServletResponse.getWriter().write(JSONObject.toJSONString(map));
  45.  
    return false;
  46.  
     
  47.  
    }
  48.  
     
  49.  
     
  50.  
    }
  51.  
     
  52.  
    // 试图渲染之后执行
  53.  
    @Override
  54.  
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
  55.  
     
  56.  
    }
  57.  
     
  58.  
    // 在请求处理之后,视图渲染之前执行
  59.  
    @Override
  60.  
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
  61.  
     
  62.  
    }
  63.  
     
  64.  
     
  65.  
    }
  1.  
    package com.constant;
  2.  
     
  3.  
    import java.util.HashMap;
  4.  
    import java.util.Map;
  5.  
     
  6.  
    public class TokenConstant {
  7.  
     
  8.  
    private static Map<String,String> map=new HashMap();
  9.  
     
  10.  
     
  11.  
    public static String getToken(){
  12.  
    return map.get("token");
  13.  
    }
  14.  
     
  15.  
    public static void updateTokenMap(String token){
  16.  
    map.put("token",token);
  17.  
    }
  18.  
     
  19.  
     
  20.  
    }

注册拦截器:

  1.  
    package com.adapter;
  2.  
     
  3.  
    import com.interceptor.LoginInterceptor;
  4.  
    import org.springframework.beans.factory.annotation.Autowired;
  5.  
    import org.springframework.context.annotation.Configuration;
  6.  
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
  7.  
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  8.  
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
  9.  
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  10.  
     
  11.  
     
  12.  
    @Configuration
  13.  
    public class LoginAdapter implements WebMvcConfigurer {
  14.  
     
  15.  
     
  16.  
    //解决跨域问题
  17.  
    @Override
  18.  
    public void addCorsMappings(CorsRegistry registry) {
  19.  
    registry.addMapping("/**")
  20.  
    .allowedHeaders("Content-Type","X-Requested-With","accept,Origin","Access-Control-Request-Method","Access-Control-Request-Headers","token")
  21.  
    .allowedMethods("*")
  22.  
    .allowedOrigins("*")
  23.  
    //是否允许使用cookie
  24.  
    .allowCredentials(true);
  25.  
    }
  26.  
     
  27.  
     
  28.  
     
  29.  
     
  30.  
    @Autowired
  31.  
    private LoginInterceptor loginInterceptor;
  32.  
     
  33.  
     
  34.  
    // 这个方法是用来配置静态资源的,比如html,js,css,等等
  35.  
    @Override
  36.  
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
  37.  
    }
  38.  
     
  39.  
     
  40.  
     
  41.  
    // 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
  42.  
    @Override
  43.  
    public void addInterceptors(InterceptorRegistry registry) {
  44.  
    System.out.println("进入拦截器");
  45.  
    //addPathPatterns是表明拦截哪些请求
  46.  
    //excludePathPatterns是对哪些请求不做拦截
  47.  
    registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/user/login");
  48.  
    }
  49.  
     
  50.  
    }

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

前端代码概要:

前端用的VUE

  1.  
    <template>
  2.  
    <div class="login">
  3.  
    <!--打包时用这个-->
  4.  
    <div class="welcome"><img src="/dist/static/image/welcome.png"></div>
  5.  
    <!--本地用这个-->
  6.  
    <!--<div class="welcome"><img src="/static/image/welcome.png"></div>-->
  7.  
    <div class="login-form">
  8.  
    <div class="login-inp"><label>账号</label><input type="text" placeholder="请输入账号" v-model="user.account"></div>
  9.  
    <div class="login-inp"><label>密码</label><input type="password" placeholder="请输入密码" v-model="user.password"></div>
  10.  
     
  11.  
    <div class="login-inp" v-show="!loadingShow" v-on:click="ok()">
  12.  
    <input type="button" value="立即登录" />
  13.  
    </div>
  14.  
    </div>
  15.  
    <!--加载效果-->
  16.  
    <wv-loadmore v-show="this.loadingShow"></wv-loadmore>
  17.  
     
  18.  
     
  19.  
    </div>
  20.  
    </template>
  21.  
     
  22.  
    <script>
  23.  
    import Vue from ‘vue‘;
  24.  
    import Axios from ‘axios‘
  25.  
    import { Toast } from ‘we-vue‘
  26.  
    export default {
  27.  
    name: ‘Login‘,
  28.  
    data: function () {
  29.  
    return {
  30.  
    user: {account: ‘‘, password: ‘‘},
  31.  
    show: false,
  32.  
    url:this.GLOBAL.loginUrl,
  33.  
    isDisable:false,
  34.  
    loadingShow:false
  35.  
    }
  36.  
    },
  37.  
    methods: {
  38.  
    ok: function () {
  39.  
    if (!this.user.account || !this.user.password) {
  40.  
    // Toast.loading(‘加载中‘);
  41.  
    Toast.text(‘请完善登陆信息‘);
  42.  
    console.log(‘param not allow null‘)
  43.  
    return
  44.  
    };
  45.  
     
  46.  
    this.isDisable=true;
  47.  
    this.loadingShow=true;
  48.  
     
  49.  
     
  50.  
     
  51.  
     
  52.  
    setTimeout(() => {
  53.  
     
  54.  
    Axios.post(this.url,
  55.  
    this.user,
  56.  
    { //方式2通过transformRequest方法发送数据,本质还是将数据拼接成字符串
  57.  
    transformRequest:[
  58.  
    function(data){
  59.  
    let params=‘‘;
  60.  
    for(let index in data){
  61.  
    params+=index+‘=‘+data[index]+‘&‘;
  62.  
    }
  63.  
    return params;
  64.  
    }
  65.  
    ]
  66.  
    })
  67.  
    .then(response => {
  68.  
    if (response.data) {
  69.  
    //存储token
  70.  
    localStorage.setItem(‘accessToken‘, response.data);
  71.  
    this.$router.push({ path: ‘home‘ })
  72.  
    }else {
  73.  
    Toast.fail(‘登陆失败‘);
  74.  
    console.log(‘登陆失败:‘, response.data.message)
  75.  
    }
  76.  
    this.loadingShow=false;
  77.  
    this.isDisable=false;
  78.  
    })
  79.  
    .catch(error => {
  80.  
    Toast.fail(‘请求失败‘);
  81.  
    console.log(‘请求失败:‘, error)
  82.  
    this.loadingShow=false;
  83.  
    this.isDisable=false;
  84.  
    })
  85.  
     
  86.  
    }, 1000)
  87.  
     
  88.  
     
  89.  
     
  90.  
     
  91.  
     
  92.  
     
  93.  
    },
  94.  
    cancel: function () {
  95.  
    this.show = false
  96.  
    this.$emit(‘cancel‘, this.flowParam)
  97.  
    }
  98.  
     
  99.  
    }
  100.  
    }
  101.  
     
  102.  
    </script>
  103.  
     

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

每次请求都放到header中:

此处简写:

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

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

以上是关于java基于token验证之登陆验证的主要内容,如果未能解决你的问题,请参考以下文章

Android携带token登陆验证与刷新token

登陆权限--token 的生成和验证

登陆权限--token 的生成和验证

App登陆java后台处理和用户权限验证

登陆页面的验证码生成与验证

cms-登陆