Eureka用于服务的注册于发现
Feign支持服务的调用以及均衡负载
Hystrix处理服务的熔断防止故障扩散
后端服务往往不直接开放给调用端,而是通过一个API网关根据请求的url,路由到相应的服务。
当添加API网关后,在第三方调用端和服务提供方之间就创建了一面墙,这面墙直接与调用方通信进行权限控制,后将请求均衡分发给后台服务端。
网关(Gateway)又称网间连接器、协议转换器。网关在网络层以上实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关既可以用于广域网互连,也可以用于局域网互连。
网关是一种充当转换重任的计算机系统或设备。使用在不同的通信协议、数据格式或语言,甚至体系结构完全不同的两种系统之间,网关是一个翻译器。
Zuul 是Netflix
提供的一个开源组件,致力于在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。也有很多公司使用它来作为网关的重要组成部分。Spring
Cloud 体系收录的该模块,主要用于提供动态路由、监控、安全控制、限流配额等,可以将内部微服务API统一暴露。
在spring cloud 体系当中,内部的服务全部进行隐藏,对外只有一个对外暴露的机制,这就是spring cloud zuul
网关。架构图如下所示
Zuul
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 加入网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
user里测试
<!--JWT-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
server:
port: 7000
spring:
application:
name: zuul
cloud:
config:
name: me-config
profile: dev
discovery:
enabled: true
service-id: config
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka
@SpringBootApplication
//标注当前是网关
@EnableZuulProxy
@EnableDiscoveryClient
@Component
public class AuthorZuulFilter extends ZuulFilter{
//指定当前过滤器的类型
/*PRE:在请求被路由之前调用,可以使用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试Log等。
*ROUTE:将请求路由到对应的微服务,用于构建发送给微服务的请求。
*POST:在请求被路由到对应的微服务以后执行,可用来为Response添加HTTP Header、将微服务的Response发送给客户端*等。
*ERROR:在其他阶段发生错误时执行该过滤器。
*/
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
//指定过滤器的执行顺序
@Override
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER;
}
//配置是否启用
@Override
public boolean shouldFilter() {
//全部都拦截
return true;
}
//指定过滤器中的具体业务代码
@Override
public Object run() throws ZuulException {
System.out.println("拦截,无法访问!");
return null;
}
}
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestJWT {
//加密
@Test
public void testSecert(){
long l = System.currentTimeMillis();
l+=5*60*1000;
Date date = new Date(l);
//定义加密的算法 私钥
Algorithm algorithmHS = Algorithm.HMAC256("secret");
Map map = new HashMap<>();
map.put("alg","HS256");
map.put("typ","jwt");
//头部部分
String token = JWT.create().withHeader(map).
//主体 载荷
//创建的主题
withSubject("this is token").
//创建者
withIssuer("wang").
//签发的时间
withIssuedAt(new Date()).
//自定义的信息
withClaim("username","张三").
withClaim("userpass",2).
//过期时间
withExpiresAt(date).
//签名
sign(algorithmHS);
System.out.println("==========================="+token);
}
@Test
public void Verify(){
String token = "eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0aGlzIGlzIHRva2VuIiwidXNlcnBhc3MiOjIsImlzcyI6IndhbmciLCJleHAiOjE2MDMyOTE1MDksImlhdCI6MTYwMzI5MTIwOSwidXNlcm5hbWUiOiLlvKDkuIkifQ.Bvu0uFaPKY8ZotSZUY1yXtks6xSBop7xA2yvN5wdfrA";
Algorithm algorithm = Algorithm.HMAC256("secret");
JWTVerifier verfiy = JWT.require(algorithm).withIssuer("wang").build();
//解析token
DecodedJWT verify = verfiy.verify(token);
//获取你所需要的内容
Claim username = verify.getClaim("username");
Claim userpass = verify.getClaim("userpass");
System.out.println("当前用户名为 ===="+username.asString()+"用户密码为========"+userpass.asInt());
}
}
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 加入网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>com.wo</groupId>
<artifactId>pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>
server:
port: 7000
spring:
application:
name: zuul
cloud:
config:
name: me-config
profile: dev
discovery:
enabled: true
service-id: config
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka
@SpringBootApplication
//标注当前是网关
@EnableZuulProxy
@EnableDiscoveryClient
@Component
public class AuthorZuulFilter extends ZuulFilter{
//指定当前过滤器的类型
/*PRE:在请求被路由之前调用,可以使用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试Log等。
*ROUTE:将请求路由到对应的微服务,用于构建发送给微服务的请求。
*POST:在请求被路由到对应的微服务以后执行,可用来为Response添加HTTP Header、将微服务的Response发送给客户端*等。
*ERROR:在其他阶段发生错误时执行该过滤器。
*/
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
//指定过滤器的执行顺序
@Override
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER;
}
//配置是否启用
@Override
public boolean shouldFilter() {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
String requestURI = request.getRequestURI();
if ("/user/login".equals(requestURI)){
return false;
}
return true;
}
//指定过滤器中的具体业务代码
@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
Cookie[] cookies = request.getCookies();
String token=null;
for (Cookie cook:cookies
) {
if (cook.getName().equals("token")){
token= cook.getValue();
}
}
//定义返回值
BaseResp baseResp = new BaseResp();
try {
Algorithm algorithm = Algorithm.HMAC256("secret");
JWTVerifier verfiy = JWT.require(algorithm).withIssuer("wang").build();
//解析token
DecodedJWT verify = verfiy.verify(token);
//获取你所需要的内容
Claim username = verify.getClaim("username");
Claim userid = verify.getClaim("userpass");
if (username==null&&userid==null){
currentContext.getResponse().setContentType("application/json");
baseResp.setCode(10002l);
baseResp.setMessage("token验证失败,被拦截");
currentContext.setResponseBody(JSONObject.toJSONString(baseResp));
}
}catch (Exception ex){
baseResp.setCode(10003l);
baseResp.setMessage("token过期,请重新登录");
currentContext.getResponse().setContentType("application/json");
currentContext.setResponseBody(JSONObject.toJSONString(baseResp));
}
return null;
}
}
<!--JWT-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.11.0</version>
</dependency>
server:
port: 8003
spring:
application:
name: user
cloud:
config:
name: me-config
profile: dev
discovery:
enabled: true
service-id: config
feign:
hystrix:
enabled: true #开启降级
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka
#开启配置自动刷新
management:
endpoints:
web:
exposure:
include: refresh
public interface UserRespository extends JpaRepository<TrUser,Integer> {
TrUser findByLoginNameAndPassword(String loginName, String password);
}
public interface UserService {
BaseResp login(TrUser user);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserRespository userRespository;
@Override
public BaseResp login(TrUser user) {
TrUser byLoginNameAndPassword = userRespository.findByLoginNameAndPassword(user.getLoginName(), user.getPassword());
BaseResp baseResp = new BaseResp();
if (byLoginNameAndPassword!=null){
//如果user对象不为空,说明用户名,密码输入正确,将用户名,密码放置到jwt生成token
long l = System.currentTimeMillis();
l+=60*60*1000;
Date date = new Date(l);
//定义加密的算法 私钥
Algorithm algorithmHS = Algorithm.HMAC256("secret");
Map map = new HashMap<>();
map.put("alg","HS256");
map.put("typ","jwt");
//头部部分
String token = JWT.create().withHeader(map).
//主体 载荷
//创建的主题
withSubject("this is token").
//创建者
withIssuer("wang").
//签发的时间
withIssuedAt(new Date()).
//自定义的信息
withClaim("username",byLoginNameAndPassword.getLoginName()).
withClaim("userpass",byLoginNameAndPassword.getPassword()).
//过期时间
withExpiresAt(date).
//签名
sign(algorithmHS);
baseResp.setCode(200l);
baseResp.setMessage(token);
return baseResp;
}
baseResp.setCode(10001l);
baseResp.setMessage("用户密码或者账户有误");
return baseResp;
}
}
package com.wo.controller;
import com.wo.client.GoodsClient;
import com.wo.client.ShopCartClient;
import com.wo.pojo.BaseResp;
import com.wo.pojo.Goods;
import com.wo.pojo.TrUser;
import com.wo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RefreshScope//开启配置刷新 用post请求http://localhost:8003/actuator/refresh刷新配置
public class UserController {
@Autowired
GoodsClient goodsClient;
@Autowired
UserService userService;
@Autowired
ShopCartClient shopCartClient;
//user直接调用goods的findAll方法 user->goods
@RequestMapping("/user/findAll")
public List<Goods> findAll(){
return goodsClient.findAll();
}
//shopcart调用goods的findAll方法,user调用shopcart的findAndfind方法 user->shopcart->goods
@RequestMapping("/user/findAndfind")
public String findAndfind(){
return shopCartClient.findAndfind()+"****user调用shopcart的findAndfind方法成功";
}
@RequestMapping("/login")
public BaseResp login(@RequestBody TrUser user){
return userService.login(user);
}
}
npm install axios
npm install vue-cookie
npm i element-ui -s
proxyTable: {
'/api': {
target: 'http://localhost:7000/', // 设置你调用的接口域名和端口号
changeOrigin: true, // 跨域
pathRewrite: {
'^/api': '/'
}
}
},
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import cookie from 'vue-cookie'
Vue.config.productionTip = false
Vue.use(ElementUI);
Vue.use(cookie)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: {
App },
template: ' '
})
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import index from '@/components/index'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/index',
name: 'index',
component: index
}
]
})
<template>
<div class="hello">
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="用户名">
<el-input v-model="form.loginName"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import axios from 'axios'
export default {
data () {
return {
form:{
}
}
},
methods:{
onSubmit:function () {
axios.post("api/user/login",this.form).then(res=>{
//登录成功
if (res.data.code==200){
var token = res.data.message;
//将token设置到cookie中
this.$cookie.set("token",token)
this.$router.push("/index")
}else{
alert(res.data.message)
}
})
}
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
<template>
<div></div>
</template>
<script>
import axios from 'axios'
//设置让axios 携带cookie去请求后端
axios.defaults.withCredentials=true
export default {
name: "",
data(){
return{
}
},
methods:{
findAll:function () {
axios.get("api/goods/findAll").then(res=>{
if (res.data.code==200){
alert(res.data.message)
} else{
alert(res.data.message)
this.$router.push("/")
}
})
}
},
mounted(){
this.findAll();
}
}
</script>
<style scoped>
</style>