使用token登陆认证流程

首先在登陆的时候自动将用户信息作为载荷,密码作为密钥生成token并传给前端


//生成token的类
public class Token {
    public static String getToken(String password){
        return JWT.create().withAudience("aa","bb","cc")          //将这三个数据放进去作为载荷进行加密
                .withExpiresAt(DateUtil.offsetHour(new Date(),2))        //传入当前时间对象,并指定两小时后token过期
                                                           //也可以指定时分秒天,比如offsetSecond就表示指定有效期为秒
                .sign(Algorithm.HMAC256(password));        //使用用户密码作为token的密钥
    }
}

//登陆
public Result login(User usermessage) {         //登陆接口
       User user=userMapper.login(usermessage.getUsername());      //根据用户名查用户信息
        if(user==null){
            return new Result(-1,"用户名错误,请重新输入",null);
        }else{
            if(user.getPassword().equals(usermessage.getPassword())){       //将传入的密码和查询到的密码进行比对
                String token= Token.getToken(user.getPassword());       //生成token
                user.setToken(token);        //传递到user中一起传给前端

                return new Result(1,"登陆成功",user);

            }else{
                return new Result(-1,"密码错误",null);
            }
        }

    }

然后在前端接收到token并通过localStorage进行保存


 login(){
   this.$refs.aa.validate(a=>{
         if(a){
           this.http.post("/user/login",this.user).then(res=>{
             if(res.code>0){
               console.log(res.data)
               localStorage.setItem("user",JSON.stringify(res.data))     //将数据存储到本地浏览器中

              this.$router.push("/")      //登陆成功
               this.$message.success(res.msg)
             }else{
               this.$message.warning(res.msg)      //登陆失败
             }


           })

         }
    })

  },

 

然后在请求拦截器中将token进行添加, 这样每次请求就都会携带token了


const http=axios.create({
  baseURL: '/x',         //在这里加入前缀后,所有写的接口都会自动拼接上这个前缀, 你也可以在这里拼接上目标地址http://localhost:8080
                   //其实就是当你没有指定具体服务器地址的话,它就会拼接上当前vue运行的地址
  timeout:3000            //规定最大请求时间为3秒
})



//request请求拦截器
http.interceptors.request.use(config=>{

  config.headers["Content-Type"]="application/json;charset=utf-8"           //添加请求头
  var user=localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")):null

  if(user){       //只有登陆了才会将用户信息user进行存储,这里就相当于判断是否登陆了
    var token=user.token        //获取后端生成的token
    config.headers.token=user.token    //在请求头中添加token
  }

  return config
},error=>{
  return Promise.reject(error)
})

然后在后端设置拦截器用来验证token


//这是拦截器的具体的方法
@Controller
public class ProjectInterceptor  implements HandlerInterceptor {

    @Resource
    private UserMapper userMapper;



    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //首先要确定访问的是一个方法
        if(!(handler instanceof HandlerMethod)){  //这里表示当访问的是一个html页面的时候就直接结束,当访问的是一个方法的时候才会继续向下运行
                            //比如拦截"/**"请求,然后访问/aa.html此时就会直接结束,但是访问的是/aa这个方法的话,就会打印"开始拦截"
            return true;
        }


        //然后判断请求中是否有token
        String token=request.getHeader("token");      //从请求头中获取token
        if(StrUtil.isBlank(token)){       //主要用来判断字符串类型的变量是否为空
              throw  new ServiceException(-1,"无token,请重新登陆");
        }



        //然后解析token中的载荷,但这一步无法判断token是否过期
        String Username;
        try {
           List<String> ff = JWT.decode(token).getAudience();     //解析token中的主体中的数据,结果为["aa","bb","cc"],就是之前加密的那三个数据
            Username= ff.get(0);      //解析token从中获取载荷中的第一个数据,如果这串代码运行异常则说明该token字符串有问题
        } catch (Exception e) {
           throw  new ServiceException(-1,"token验证失败,请重新登陆");   //此时说明token字符串已经被串改,导致解析失败
        }


        //通过用户名查询信息
        User user=userMapper.login(Username);       //根据解析的用户名查询数据
        if(user==null){
            throw new ServiceException(-1,"用户不存在,该token不合法");
        }


        //验证token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();     //通过添加密钥来创建验证对象,从而验证token是否过期,因为即使过期了,上面也能解析到数据
        try {
            jwtVerifier.verify(token);
        } catch (JWTVerificationException e) {
            throw new ServiceException(-1,"token已过期,请重新登陆");
        }


        System.out.println("开始拦截");

        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

、

、

、

//这是注册上面的拦截器
@Controller
public class SpringMvcSupport implements WebMvcConfigurer {
    @Resource
    private ProjectInterceptor  PI;


    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(PI).addPathPatterns("/**").excludePathPatterns("/NPA/**");  //这里是注册拦截器,并放行/NPA开头的请求
    }
}

总体流程就是:

生成token--->前端保存token------>通过前端的拦截器给请求头添加token----->后端通过拦截器验证token。

 

验证token主要有:

1,请求头中是否有token

2,token是否被篡改,(也就是看是否能够正常的解析token)

3,token是否合法,(也就是看解析后的数据是否是你所保存的数据)

4,token是否过期,( 即使token过期了,也能正常的解析到数据)

 

 

 

 

 

 

登陆页面


<template>
   <div  class="box">

<!--       登陆-->
        <div  class="container">
          <h1 style="margin:20px 0;font-size:40px;"><b>登陆</b></h1>
          <el-form :label-position="right" style="width:350px;margin:0 30px;" label-width="70px" :model="user" :rules="rules"  ref="aa"  >
            <el-form-item label="用户名:"  prop="username">
              <el-input type="text" v-model="user.username" ></el-input>
            </el-form-item>

            <el-form-item label="密码:"  prop="password">
              <el-input show-password v-model="user.password"></el-input>
            </el-form-item>
          </el-form>

          <div style="margin-bottom: 50px;">
            <el-button type="primary"  @click="login">登陆</el-button>
            <el-button type="primary"  @click="$router.push('/register')">前往注册</el-button>
          </div>
        </div>

   </div>
</template>

<script>
    export default {
        name: "Login",
      data(){
          return{
            user:{},        //表单数据
            rules:{
              username:[
                {required:true,message:'请输入用户名',trigger:"blur"},
                {min:3,max:15,message:"字符在3到5之间"}
              ],
              password:[
                {required:true,message:"请输入密码",trigger:"blur"},
                {max:15,message:"密码最大不超过15"}
              ]
            }
          }
      },
      methods:{
          login(){
           this.$refs.aa.validate(a=>{
                 if(a){
                   this.http.post("/NPV/login",this.user).then(res=>{
                     if(res.code>0){
                       console.log(res.data)
                       localStorage.setItem("user",JSON.stringify(res.data))     //将数据存储到本地浏览器中
                       localStorage.setItem("token",res.data.token)         //保存token

                       this.$router.serRouter();        //设置路由

                      this.$router.push("/")      //登陆成功

                       this.$message.success(res.msg)
                     }else{
                       this.$message.warning(res.msg)      //登陆失败
                     }


                   })

                 }
            })

          },
      }
    }
</script>

<style scoped>
    .box{
      height:100vh;
      overflow:hidden;
      display:flex;
      justify-content: center;
      align-items:center;
      background:linear-gradient(200deg,#f3e7e9,#e3eeff)
    }
  .container{
    background:#fff;
    border-radius: 15px;

    display:flex;
    flex-direction: column;
    align-items:center;
  }

</style>

 

 

注册


<template>
   <div  class="box">

<!--       注册-->
        <div  class="container">
          <h1 style="margin:20px 0;font-size:40px;"><b>注册</b></h1>
          <el-form   :model="user" :rules="rules"    style="width:350px;margin:0 30px"  ref="bb">
            <el-form-item    prop="username">
              <el-input  placeholder="用户名" type="text" v-model="user.username" ></el-input>
            </el-form-item>

            <el-form-item   prop="email"  style="position:relative">
              <el-input  placeholder="输入邮箱获取验证码" type="text" v-model="user.email" ></el-input>
<!--              获取验证码-->
              <el-button style="position: absolute;top:0;right:0;height:43px;" @click="validate">{{value}}</el-button>
            </el-form-item>

            <el-form-item   prop="varification">
              <el-input placeholder="输入验证码" show-password v-model="user.varification"></el-input>
            </el-form-item>

            <el-form-item   prop="password">
              <el-input placeholder="密码" show-password v-model="user.password"></el-input>
            </el-form-item>


            <el-form-item   prop="Confirmpassword">
              <el-input placeholder="确认密码" show-password v-model="user.Confirmpassword"></el-input>
            </el-form-item>




          </el-form>

          <div style="margin-bottom: 50px;">
            <el-button type="primary"  @click="register">注册</el-button>
            <el-button type="primary" @click="$router.push('/login')">返回登陆</el-button>
          </div>
        </div>

   </div>
</template>

<script>


    export default {
        name: "Login",
      data(){
          return{
            user:{},        //表单数据
            value:"获取验证码",
            rules:{
              username:[
                {required:true,message:'请输入用户名',trigger:"blur"},
                {min:3,max:15,message:"字符在3到5之间"}
              ],
              password:[
                {required:true,message:"请输入密码",trigger:"blur"},
                {max:15,message:"密码最大不超过15"}
              ],
              Confirmpassword:[
                {required:true,message:"请确认密码",trigger:"blur"},
                {max:15,message:"密码最大不超过15"},
                {validator:this.aa}
              ],
              email:[
                {required:true,message:"请输入邮箱",trigger:"blur"},
                {type: 'email',message: "邮箱格式不正确"}
              ],

              varification:[
                {required:true,message:"请输入验证码"}
              ]

            }
          }
      },
      methods:{
        aa(rule,val,callback){         //字段Confirmpassword的回调函数
           if(val!==this.user.password){
             callback(new Error("两次输入的密码不一致"))
           }
           return  callback()
        },
         register(){          //注册
            this.$refs.bb.validate(val=>{
              if(val){
                 this.http.post("/NPV/register?varification="+this.user.varification,this.user).then(res=>{
                   console.log(res)
                      if(res.code>0){
                        this.$router.push("/login")
                        this.$message.success(res.msg)

                      }else{
                        this.$message.warning(res.msg)
                      }
                 }).catch(()=>{
                   this.$message.error("注册失败")
                 })
              }
            })

         },

      },
      computed:{
        validate(){          //获取验证码
          var flag=true

          return ()=>{
            if(flag) {
              var count = 60
              this.value = count + "秒后重新获取"
              flag=false
              var that = this
              this.http.get("/NPV/varification?email="+this.user.email)
              var timer = setInterval(function () {
                if (count > 0) {
                  count--
                  that.value= count + "秒后重新获取"
                } else {
                  clearInterval(timer)
                  that.value = "请重新获取"
                  flag=true
                }
              }, 1000)
            }
          }

        },

      }
    }
</script>

<style scoped>
    .box{
      height:100vh;
      overflow:hidden;
      display:flex;
      justify-content: center;
      align-items:center;
      background:linear-gradient(200deg,#f3e7e9,#e3eeff)
    }
  .container{
    background:#fff;
    border-radius: 15px;

    display:flex;
    flex-direction: column;
    align-items:center;
  }

</style>

 

       其实简单来说token就是一个具有时间期限的,可以让你拿到里面数据的字符串,   

       还有一种更简单的方式,结合redis,在登录的时候,自动生成一个字符串作为redis的键名并保存数据,设置保存在redis的时间为7天,

       此时这个redis键名就可以作为token传给前端,前端在请求的时候,拦截器进行拦截并判断是否有token,有的话则通过该token从redis中查询数据,能查询到则该token就是合法的,则表示你已经正常登录了。

      当然7天过后,你再通过这个token从redis中查询数据,将无法查询到,此时就会让你重新登录。

       总之,token就是可以让你拿到数据的,具有时间期限的字符串

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值