网上看到的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,才能访问接口的数据
我的过期时间设置一天,我放到配置文件里了,过期时间可以自己随意设置