目录
思路分析
会话保持
步骤
思路分析
1.用户通过访问微服务网关调用微服务,同时携带头文件信息
2.在微服务网关这里进行拦截,拦截后获取用户要访问的路径
3.识别用户访问的路径是否需要登录,如果需要,识别用户的身份是否能访问该路径[这里可以基于数据库设计一套权限]
4.如果需要权限访问,用户已经登录,则放行
5.如果需要权限访问,且用户未登录,则提示用户需要登录
6.用户通过网关访问用户微服务,进行登录验证
7.验证通过后,用户微服务会颁发一个令牌给网关,网关会将用户信息封装到头文件中,并响应用户
8.用户下次访问,携带头文件中的令牌信息即可识别是否登录
会话保持
用户每次请求的时候,我们都需要获取令牌数据,方法有多重,可以在每次提交的时候,将数据提交到头文件中,也可以将数据存储到Cookie中,每次从Cookie中校验数据,还可以每次将令牌数据以参数的方式提交到网关,这里面采用Cookie的方式比较容易实现。
步骤
- 登录封装Cookie
/*** *用户登录 */
@RequestMapping(value = "/login")
public Result login(String username, String password, HttpServletResponse response){
//查询用户信息
User user = userService.findByUsername(username);
if(user!=null && BCrypt.checkpw(password,user.getPassword())){
//设置令牌信息
Map<String,Object> info=new HashMap<>();
info.put("role","USER");
info.put("success","SUCCESS");
info.put("username",username);
//生成令牌
String jwt = JwtUtil.createJWT(UUID.randomUUID().toString(),
JSON.toJSONString(info), null);
//创建Cookie对象
Cookie cookie = new Cookie("Authorization",jwt);
//设置cookie的路径
cookie.setPath("/");
//把cookie使用响应头设置给浏览器
response.addCookie(cookie);
return new Result(true,StatusCode.OK,"登录成功!",jwt);
}
return new Result(false,StatusCode.LOGINERROR,"账号或者密码错误!");
}
- 修改user微服务,每次登录的时候,添加令牌信息到Cookie中,修改dongyimai-user-service的
com.offcn.user.controller.UserController
的login
方法
- 过滤器获取令牌数据
• package xin.yi.filter;
import io.jsonwebtoken.Claims; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpCookie; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import xin.yi.utils.JwtUtil;
/**• @program: dongyimai-parent
• @description:
• @author: xin yi
• @create: 2021-08-14 21:24 */ @Component public class AuthorizeFilter implements GlobalFilter, Ordered {
/设置令牌头名字/ private static final String AUTHORIZE_TOKEN = "Authorization";
/**• 全局过滤器
• @param exchange
• @param chain
• @return / @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { /设置Request、Response对象*/ ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse();
/获取请求的URI/ String path = request.getURI().getPath();
/**• 如果是登录、goods等开放的微服务[这里的goods部分开放],则直接放行,这里不做完整演示,完整演示需要设计一套权限系统 / if (path.startsWith("/api/user/login") || path.startsWith("/api/brand/search/")){ /放行*/ Mono<Void> filter = chain.filter(exchange); return filter; }
/获取头文件中的令牌信息/ String tokent = request.getHeaders().getFirst(AUTHORIZE_TOKEN);
/**
• 如果头文件中没有,则从请求参数中获取 */ if (StringUtils.isEmpty(tokent)){ tokent = request.getQueryParams().getFirst(AUTHORIZE_TOKEN); }
/**
* 从cookie中获取令牌数据
*/
HttpCookie first = request.getCookies().getFirst(AUTHORIZE_TOKEN);
if (null != first){
tokent = first.getValue();
}
/**
* 如果为空,则输出错误代码
*/
if (StringUtils.isEmpty(tokent)){
/*设置方法不允许被访问,405错误代码*/
response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED);
return response.setComplete();
}
/**
* 解析令牌数据
*/
try {
Claims claims = JwtUtil.parseJWT(tokent);
/*在令牌信息校验那块将令牌加入到请求头中*/
request.mutate().header(AUTHORIZE_TOKEN,claims.toString());
} catch (Exception e) {
e.printStackTrace();
/*解析失败响应401错误*/
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
/*放行*/
return chain.filter(exchange);
}
/**
* 过滤器执行顺序
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
- 每次在网关中通过过滤器获取Cookie中的令牌,然后对令牌数据进行解析,修改微服务网关dongyimai-gateway-web中的AuthorizeFilter
- 添加Header信息
• Claims claims = JwtUtil.parseJWT(token); //把解析出来的令牌添加到头文件中 request.mutate().header(AUTHORIZE_TOKEN,claims.toString());
• 我们还可以在Gateway的全局过滤器中添加请求头信息,例如可以将令牌信息添加到请求头中,在微服务中获取头信息
//获取请求头中封装的令牌 String token = request.getHeader("Authorization"); System.out.println("令牌信息:"+token);