后端: springboot+springcloud+jpa+redis+jwt
前端:vue
1.springCloud的使用
1.1:依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.5.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<!-- repositories also needed for snapshots and milestones -->
1.2:各个注解的功能
@EnableEurekaClient //开启eurka客户端
@EnableDiscoveryClient //发现feign客户端
@EnableFeignClients //开启feign客户端
@EnableZuulProxy //开启zuul代理
1.3: 跨服务调用:
熔断器相当于备用方案,实现client接口并重写其方法,具体使用详见官网(目前没用到,用到后补充)
2.网关的使用
2.1: 网关相当于入口,系统对外的唯一入口,用户所有的请求都会通过网关进入,因此网管最主要的功能有两个,
1.路由转发:接收一切外界请求,转发到后端的微服务上去。
2.过滤器:在服务网关中可以完成一系列的横切功能,例如权限校验、限流以及监控等,这些都可以通过过滤器完成(其实路由转发也是通过过滤器实现的。
例如鉴权,用户登录成功或发送一个jwt返回给前端,每次用户发送请求时携带该jwt,进入到网管后进行验证,若一直则可继续访问,不一致提示无法访问.
下面为zuulfilter的使用
public class WebFilter extends ZuulFilter {
@Resource
private RedisTemplate redisTemplate;
@Override
public String filterType() {
return "pre"; //在微服务网关进行转发之前j进行过滤
}
@Override
public int filterOrder() {
return 0; //数字越大,优先执行越低,0为最先执行
}
@Override
public boolean shouldFilter() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
//放行请求
if (request.getRequestURL().indexOf("login") != -1){ //如果是登录请求,不使用过滤器
return false;
}
return true; //是否执行该过滤器
}
@Override
public Object run() throws ZuulException {
//前台网管需要吧用户的身份信息token转发给具体的微服务进行验证
//而使用网关时是获取不到消息头的
//需要在这个过滤器中,拿到用户信息
RequestContext currentContext = RequestContext.getCurrentContext();
//获取用户原来的请求
HttpServletRequest request = currentContext.getRequest();
//获取y用户信息
String header = request.getHeader("Authorization");
String token = header.substring(7);
//获取用户id
String userHeader = request.getHeader("userId");
//进行校验
if (!token.equals(redisTemplate.boundValueOps(userHeader).get())){
//读取的token和该用户生成的token不同,token无效
System.out.println("非法token");
}
//转发token,转发到后端的微服务时同时也需要带上token。
currentContext.addZuulRequestHeader("Authorization",header);
return null;
}
}
网关的配置:
3.jwt鉴权
3.1 在用户登陆成功后需要生成jwt,用于鉴别用户身份.
当用户通过发请求的方式访问到后端时,会优先通过网关,同时发请求的过程中是携带token进行验证的.
然而还有一种情况,就是用户发请求后,后端的微服务之间的互相进行调用,在后端自行调用的过程中用户是没有发送第二次请求的,因此也不会有token,再次进入到网关时会鉴权失败.
解决方法:
流程: 用户 —> 微服务A —>调用微服务B
1.在微服务A 中自定义拦截器 实现AccessDecisionManager,HandlerInterceptor
重写 decide(Authentication authentication, Object object, Collection configAttributes)方法(具体执行如下)
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
// TODO Auto-generated method stub
if(object instanceof FilterInvocation) {
FilterInvocation invocation = (FilterInvocation)object;
HttpServletRequest request = invocation.getHttpRequest();
String header = request.getHeader("Authorization");
//2. 判断获取到的值是否为空
if (header == null || "".equals(header)) {
throw new AccessDeniedException("");
}
//3. 判断获取到的值是否合法,判断是否以Bearer + 空格开头
if (!header.startsWith("Bearer ")) {
throw new AccessDeniedException("");
}
//4. 获取token的值,进行解析,使用jwtutil工具类进行解析
String token = header.substring(7);
System.out.println("token为: "+token);
try {
Claims claims = jwtUtil.parseJWT(token);
//5.判断解析的claims是否为空
if (claims == null) {
throw new AccessDeniedException("");
}
System.out.println(claims.get("roles"));
request.setAttribute("claims",claims);
request.setAttribute("token",token);
return;
} catch (Exception e) {
e.printStackTrace();
}
}
throw new AccessDeniedException("");
}
这个其实很简单,微服务A是用户发请求的,自然是有请求头的,在A服务中获取请求头,然后将token解析出来,claims是在JwtUtil中定义的,为解析完token后的对象,可通过claims.get(“roles”)获取用户信息