3.4. 拦截器实现及cookie解密并验证

未匹配的标注

上一节课我们讲过了为什么使用cookie代替session,很多SX说cookie不安全,不建议用cookie,一定要用session,那是骗鬼的哈!看你怎么用!大流量高并发情况下你服务器读取session就会浪费很多资源,cookie反而是分布存储到了用户自己的电脑浏览器,这样对你服务器没有任何压力,不香吗?
既然将了如何加密cookie保证绝对安全防止cookie被篡改那么就有招数解密cookie实现登录验证,当然不能单纯的去讲如何实现解密cookie实现登录验证,这里我们捎带着把iris当中实现拦截器的功能带出来!
因为我们一直在强调分布式,所以呢,我们这里的权限验证单独做成一个服务,这样耦合度大大降低,不是很好吗?这里只讲如何实现架构上的调整以及解密cookie实现登录验证,至于分布式权限验证,看好了哈,是分布式权限验证,这个我们今天不讲,比较费劲,还没想好要不要以博客的形式发出来!

单独新建一个validate.go文件 随便你放在哪里 我是放在了项目跟目录下了

拦截器实现及cookie验证
你爱放哪放哪哈,这个无所谓
上代码:
validate.go

//分布式权限验证  需要独立运行的一个模块
package main

import (
   "errors"
 "fmt" "net/http" "product/common" "product/encrypt")

//执行正常的业务逻辑  在拦截验证完成之后走的正常逻辑
func Check(w http.ResponseWriter,r *http.Request){
   //执行正常业务逻辑
  fmt.Println("执行check!")
}
//统一验证拦截器  每个接口都需要提前验证
func Auth(w http.ResponseWriter,r *http.Request) error {
   fmt.Println("进行了验证!")
   //添加基于cookie的权限验证
  //在拦截验证器里面我们需要验证每个用户的cookie
  err:=CheckUserInfo(r)
   if err != nil {
      return err
  }
   return nil
}

//验证cookie用到的身份校验函数
func CheckUserInfo(r *http.Request) error {
   //获取uid cookie
  uidCookie,err := r.Cookie("uid")
   if err != nil {
      return errors.New("用户uid cookie 获取失败!")
   }
   //获取用户加密串
  signCookie,err := r.Cookie("sign")
   if err != nil {
      return errors.New("用户 sign 加密串获取失败!")
   }
   //对sign加密串进行解密
  signBytes, err := encrypt.DePwdCode(signCookie.Value)
   if err != nil {
      return errors.New("加密串被串改")
   }

   fmt.Println("结果比对")
   fmt.Println("用户ID:"+uidCookie.Value)
   fmt.Println("解密后的用户ID"+string(signBytes))
   //拿到解密后的值跟cookie里面的uid比对 因为我们使用uid进行的aes加密 比对正确则通过 否则失败
  if checkInfo(uidCookie.Value,string(signBytes)) {
      return nil
  }
   return errors.New("身份校验失败!")

}

//自定义逻辑判断
func checkInfo(checkStr string,signStr string) bool {
    if checkStr == signStr{
      return true
  }else{
      return false
  }
}

func main(){
   //1.过滤器
  filter := common.NewFilter()
   //注册拦截器  将我们访问的uri和FilterHandle类型绑定起来 FilterHandle类型是一个函数类型  对应关系放到了结构体里面的参数filterMap map字典当中去了
  filter.RegisterFilterUri("/check",Auth)
   filter.RegisterFilterUri("/cc",Auth)
   //2.启动服务
  //当访问/check的时候会自动去执行自定义方法 Handle(Check)并把要正常执行的函数放进去
  http.HandleFunc("/check",filter.Handle(Check))
   http.HandleFunc("/cc",filter.Handle(Check))
   //启动服务  这没啥好讲的啦
  http.ListenAndServe(":8083",nil)
}

filter.go文件
我是放在了common包里面:

拦截器实现及cookie验证
放哪里你自己看着办就行 只要在你那跑的时候都调对了就中!!!

//过滤
package common

import "net/http"

//声明一个新的数据类型(函数类型)   可以把函数当做是一种类型 这也是golang的特点
type FilterHandle func(rw http.ResponseWriter,req *http.Request) error

//拦截器结构体
type Filter struct {
    //用来存储需要拦截的URI
  filterMap map[string]FilterHandle
}

//Filter初始化函数 你可以把它理解为构造函数  有了这个构造函数那么就可以调用结构体Filter相关的方法了
func NewFilter() *Filter {
   return &Filter{filterMap:make(map[string]FilterHandle)}
}

//注册拦截器  把我们的uri和handler绑定起来
func (f *Filter) RegisterFilterUri(uri string,handler FilterHandle) {
   f.filterMap[uri] = handler
}

//根据uri获取对应的handle
func (f *Filter)  GetFilterHandle(uri string) FilterHandle {
   return f.filterMap[uri]
}

//声明新的函数类型
type WebHandle func(rw http.ResponseWriter,req *http.Request)

//执行拦截器并返回函数类型
//要去返回的是一个函数类型 返回函数其实就是在执行这个匿名函数
func (f *Filter) Handle(webHandle WebHandle) func(rw http.ResponseWriter,r *http.Request) {
   return func(rw http.ResponseWriter, r *http.Request) {
      //在函数体当中我们遍历了Filter结构体里面的filterMap map字典 因为我们在此之前执行了注册拦截器操作就是把uri和FilterHandle类型绑定起来了
  //path就是FilterHandle类型的函数 可以用来直接执行  比如这里path就是 /check  handle其实就是Auth() 那么Auth()就要和 FilterHandle类型保持一致
  for path,handle := range f.filterMap{
         //判断当前浏览器访问的路径是否和map字典里面注册进来的一致
  if path == r.RequestURI {
            //执行拦截业务逻辑  如果一直 执行拦截业务 也就是您在注册之后绑定的handle类型的函数  这里是 Auth()  err := handle(rw, r)
            //判断是否报错
  if err!= nil {
               rw.Write([]byte(err.Error()))
               return
  }
            //会不断的循环遍历map字典里面的值 一旦找到一个一样的  拦截并验证完成之后 跳出循环
  break
  }
      }
      //拦截请求并验证完成之后     执行正常注册的函数  这里正常的注册函数就是Check() 里面可以写你正常的业务逻辑
  webHandle(rw,r)
   }
}

我真的不知道该用什么语言来描述,所以就把注释写到代码里面去了,如果看注释你还不明白的话,请加qq:495681586咨询 我会耐心指导你 不过是收费的!天下没有免费的午餐,这些东西也是我自己费劲吧啦熬夜写出来的!

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~