springcloud网关拦截+redis+自定义token做登录验证操作

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dfBeautifulLive/article/details/83148737

网上看到的token做起来都太复杂,介绍说耗费的内存较大,写的封装方法非常多,看来看去非常不方便,自己就借助token思想,和网关拦截器组合操作的登录验证机制。

1.下面这段代码就是用户请求,验证数据库是否有这个用户名和密码,用户登录成功与否,成功登录就生成token存储到redis里

package gsa.rest.datacenter.rest.login;

import gsa.base.common.Enum.StatusCode;
import gsa.base.common.Utils.DataResult;
import gsa.base.datasources.Redisconfig.RedisTemplete;
import gsa.rest.datacenter.service.login.LoginService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.UUID;

/**
 * Created by df on 2018/9/28.
 */
@Controller
@Slf4j
@CrossOrigin
@RequestMapping("/login")
public class LoginController {
    private static final Logger log = LoggerFactory.getLogger(LoginController.class);
    @Autowired
    private LoginService loginService;

    @Autowired
    private RedisTemplete redisTemplete;

    @Value("${redis.expireTime}")
    private Long expireTime;//token过期时间

    @ApiOperation(value = "登录验证")
    @GetMapping(path = "/loginValidate")
    @ResponseBody
    public DataResult login(String username, String password, HttpServletResponse response) throws Exception {
        try {
            List list = loginService.login(username, password);
            if (list.size() > 0) {
                String token = TokenStorage(response, username);
                log.info("登录成功,存储token");
                return new DataResult("登录成功", StatusCode.SUCCESS.getCode(), "Bearer "+token);
            } else {
                log.info("登录失败,用户名或密码错误");
                return new DataResult("用户名或密码错误", StatusCode.SUCCESS.getCode());
            }
        } catch ( Exception e ) {
            e.printStackTrace();
        }
        return new DataResult(StatusCode.ERROR.getMessage(), StatusCode.ERROR.getCode());
    }

    public String TokenStorage(HttpServletResponse response, String username) {
        //生成token
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        //存储redis里
        redisTemplete.set(token, username, expireTime);
        return token;
    }

}

 2.下面登录完毕就该拦截一些接口了,登录的才可以访问接口,没有的判断token做相应的操作,我的拦截器是springcloud自带的拦截器,起到各个微服务统一网关的作用

package gsa.portal.gateway.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import gsa.base.datasources.Redisconfig.RedisTemplete;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;


/**
 * Created by df on 2018/10/8.
 * 拦截器,如果return null 正常访问各个微服务的接口
 * 如果被拦截器拦截将会返回处理的信息,也将不会访问日志记录
 */
@Component
public class PreZuulFilter extends ZuulFilter {
    private static final Logger log = LoggerFactory.getLogger(ZuulFilter.class);
    @Bean
    private RedisTemplete redisTemplete(){
        return new RedisTemplete();
    }
    @Autowired
    private RedisTemplete redisTemplete;

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String url = request.getRequestURL().toString();
        //获取认证名称
        String Authname =request.getHeader("Authorization");
        String token=null;
        if(Authname!=null&&!Authname.equals("")){
            //用户请求时会在头部 Authorization 传给我之前存储的token, 我用来验证
            Authname= Authname.replace("Bearer ","");
            //获取redis存储的token
            if (redisTemplete.exists(Authname)){
                //查询redis是否有token
                token= (String) redisTemplete.get(Authname);
            }
        }
        //此处判断是否要拦截**************
        //过滤登录方法
        if(url.contains("/login/loginValidate")){
             return null;
        }
        //过滤datacenter微服务
        if(url.contains("/gsa/rest/")){
            if(!url.contains("/MenuSystemTree")){
                return null;
            }
        }
        //过滤es微服务
        if(url.contains("/gsa/tool/")) {
            return null;
//            if (redisTemplete.exists("INTERFACE_FILTER_ES")) {
//                if (redisTemplete.get("INTERFACE_FILTER_ES").equals("FALSE")) {
//                }
//            }
        }
        //*******************开始拦截****************************
        log.info(String.format("%s  拦截的url: %s",request.getMethod(),url));
        //没有加认证token 就没有访问权限
        if(StringUtils.isBlank(Authname)){
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.setResponseBody("{\"code\":401,\"msg\":\"没有访问权限!\"}");
            ctx.getResponse().setContentType("text/html;charset=UTF-8");
        }else if(token==null){
            //token失效了
            //用户提供的token检测出和redis不一样
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.setResponseBody("{\"code\":401,\"msg\":\"令牌失效,请重新登录!\"}");
            ctx.getResponse().setContentType("text/html;charset=UTF-8");
        }
        //*******************结束拦截****************************
        //ctx.addZuulRequestHeader("username", username);
        return null;
    }
    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }
}

 3.访问登录接口返回的数据,将data里的数据加到请求的头部
header{
Authorization:Bearer 60a12d1f892245e5b70c9c84494b4810
}

 4.调用另一个接口,输入错误的token情况下

5.请求中没有加token的情况下

 5.直到输入正确的token,才能访问接口的数据

我的过期时间设置一天,我放到配置文件里了,过期时间可以自己随意设置

猜你喜欢

转载自blog.csdn.net/dfBeautifulLive/article/details/83148737