You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ma...@apache.org on 2019/08/08 01:30:10 UTC
[servicecomb-samples] 31/43: first commit for login and gateway
microservice
This is an automated email from the ASF dual-hosted git repository.
mabin pushed a commit to branch houserush-sample
in repository https://gitbox.apache.org/repos/asf/servicecomb-samples.git
commit fceb59e5bc3f068eb7fd2587db004c53f4ebe41c
Author: linzb0123 <li...@qq.com>
AuthorDate: Fri Aug 2 11:48:03 2019 +0800
first commit for login and gateway microservice
---
houserush/gateway/README.md | 53 +++++++++
houserush/gateway/pom.xml | 5 -
.../houserush/gateway/GatewayApplication.java | 43 ++++++++
.../practise/houserush/gateway/GatewayConfig.java | 25 +++++
.../houserush/gateway/config/LoginUrlConfig.java | 42 +++++++
.../houserush/gateway/filter/AuthorizeFilter.java | 122 +++++++++++++++++++++
.../practise/houserush/gateway/rpc/UserApi.java | 26 +++++
.../practise/houserush/gateway/rpc/po/User.java | 28 +++++
.../gateway/src/main/resources/application.yaml | 39 +++++++
.../gateway/src/main/resources/microservice.yaml | 66 +++++++++++
houserush/login/README.md | 89 +++++++++++++++
houserush/login/pom.xml | 5 +
.../practise/houserush/login/LoginApplication.java | 44 ++++++++
.../practise/houserush/login/LoginConfig.java | 26 +++++
.../practise/houserush/login/aggregate/User.java | 117 ++++++++++++++++++++
.../practise/houserush/login/api/UserApi.java | 34 ++++++
.../houserush/login/api/UserApiRestImpl.java | 61 +++++++++++
.../practise/houserush/login/dao/UserDao.java | 25 +++++
.../houserush/login/service/UserService.java | 36 ++++++
.../houserush/login/service/UserServiceImpl.java | 93 ++++++++++++++++
.../login/src/main/resources/microservice.yaml | 43 ++++++++
21 files changed, 1017 insertions(+), 5 deletions(-)
diff --git a/houserush/gateway/README.md b/houserush/gateway/README.md
new file mode 100755
index 0000000..3756401
--- /dev/null
+++ b/houserush/gateway/README.md
@@ -0,0 +1,53 @@
+## 微服务 gateway
+
+该为微服务为API网关,作为对外的唯一入口,主要负责路由转发和鉴权。
+
+### 主要功能
+
+- API入口
+- 动态路由
+- 鉴权
+- 。。。
+
+### 设计原理
+- 使用[zuul](https://github.com/Netflix/zuul/wiki)来设计实现API网关功能
+
+![API gateway工作流程](https://raw.githubusercontent.com/linzb0123/images/master/servicecomb-samples-houserush/gateway1.png)
+
+### 实现
+
+- 路由转发配置
+
+- 鉴权
+
+ - 自定义AuthorizeFilter
+
+ ```java
+ @Component
+ public class AuthorizeFilter extends ZuulFilter {
+ @Override
+ public String filterType() {
+ return "pre";
+ }
+
+ @Override
+ public int filterOrder() {
+ return 0;
+ }
+ @Override
+ public boolean shouldFilter() {
+ return true;
+ }
+ @Override
+ public Object run() {
+ //根据uri判断是否需要鉴权
+ //向认证中心登录获取token
+ //提取request的header中的Authorization字段的token
+ //向认证中心检验Authorization是否有效
+ //...
+ }
+
+
+ }
+ ```
+ [使用zuul做边缘服务](https://docs.servicecomb.io/java-chassis/zh_CN/edge/zuul.html)
\ No newline at end of file
diff --git a/houserush/gateway/pom.xml b/houserush/gateway/pom.xml
index a0c2a7c..9e256a8 100644
--- a/houserush/gateway/pom.xml
+++ b/houserush/gateway/pom.xml
@@ -54,11 +54,6 @@
<artifactId>spring-cloud-zuul-zipkin</artifactId>
</dependency>
<dependency>
- <groupId>com.auth0</groupId>
- <artifactId>java-jwt</artifactId>
- <version>3.8.1</version>
- </dependency>
- <dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
diff --git a/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/GatewayApplication.java b/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/GatewayApplication.java
new file mode 100755
index 0000000..c128606
--- /dev/null
+++ b/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/GatewayApplication.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.gateway;
+
+import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
+
+import java.text.SimpleDateFormat;
+import java.util.TimeZone;
+
+@SpringBootApplication
+@EnableZuulProxy
+@EnableServiceComb
+public class GatewayApplication {
+ public static void main(String[] args) {
+ configBeforeBoot();
+ SpringApplication.run(GatewayApplication.class, args);
+ }
+
+ private static void configBeforeBoot() {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
+ RestObjectMapperFactory.getRestObjectMapper().setDateFormat(simpleDateFormat);
+ }
+}
diff --git a/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/GatewayConfig.java b/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/GatewayConfig.java
new file mode 100755
index 0000000..87dd5e5
--- /dev/null
+++ b/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/GatewayConfig.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.gateway;
+
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class GatewayConfig {
+
+}
diff --git a/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/config/LoginUrlConfig.java b/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/config/LoginUrlConfig.java
new file mode 100755
index 0000000..c738e5f
--- /dev/null
+++ b/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/config/LoginUrlConfig.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.gateway.config;
+
+import com.netflix.config.DynamicPropertyFactory;
+import com.netflix.config.DynamicStringProperty;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+public class LoginUrlConfig {
+ private DynamicStringProperty loginUrls = DynamicPropertyFactory.getInstance()
+ .getStringProperty("gateway.loginUrls", "");
+
+ private DynamicStringProperty nologinUrls = DynamicPropertyFactory.getInstance()
+ .getStringProperty("gateway.noLoginUrls", "");
+
+ public Set<String> loginUrlsSet = new HashSet<>(Arrays.asList(loginUrls.get().split(",")));
+
+ public Set<String> nologinUrlsSet = new HashSet<>(Arrays.asList(nologinUrls.get().split(",")));
+
+ public LoginUrlConfig() {
+ //TODO runtime change set
+
+ }
+}
diff --git a/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/filter/AuthorizeFilter.java b/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/filter/AuthorizeFilter.java
new file mode 100755
index 0000000..390051e
--- /dev/null
+++ b/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/filter/AuthorizeFilter.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.gateway.filter;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.netflix.zuul.ZuulFilter;
+import com.netflix.zuul.context.RequestContext;
+import org.apache.commons.lang.StringUtils;
+import org.apache.servicecomb.provider.pojo.RpcReference;
+import org.apache.servicecomb.samples.practise.houserush.gateway.config.LoginUrlConfig;
+import org.apache.servicecomb.samples.practise.houserush.gateway.rpc.UserApi;
+import org.apache.servicecomb.samples.practise.houserush.gateway.rpc.po.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+
+@Component
+public class AuthorizeFilter extends ZuulFilter {
+
+ private static final String SECRET = "231sdfqwer21313123cafkhioerutieweirqwuqbjffbqwrwr3";
+
+ private static LoginUrlConfig loginUrlConfig = new LoginUrlConfig();
+ private static Logger log = LoggerFactory.getLogger(AuthorizeFilter.class);
+
+ @RpcReference(microserviceName = "login", schemaId = "userApiRest")
+ private UserApi userApi;
+
+ @Override
+ public String filterType() {
+ return "pre";
+ }
+
+ @Override
+ public int filterOrder() {
+ return 0;
+ }
+
+ @Override
+ public boolean shouldFilter() {
+ return true;
+ }
+
+ private RequestContext ctx;
+
+ @Override
+ public Object run() {
+ ctx = RequestContext.getCurrentContext();
+ HttpServletRequest request = ctx.getRequest();
+ String method = request.getMethod();
+ String requestUri = request.getRequestURI();
+ log.info(String.format("%s -> %s", method, requestUri));
+ requestUri = requestUri.replaceAll("\\d+", "{id}");
+
+ String key = method + " " + requestUri;
+ if (loginUrlConfig.loginUrlsSet.contains(key)) {
+ String token = request.getHeader("Authorization");
+ if (token != null && StringUtils.isNotBlank(token)) {
+ User user = userApi.verifyToken(token);
+ if (user != null) {
+ ctx.addZuulRequestHeader("customerId", String.valueOf(user.getId()));
+ ctx.addZuulResponseHeader("newAuthorization", user.getToken());
+ return null;
+ }
+ }
+ sendResponse(403, "need login!");
+ } else if (loginUrlConfig.nologinUrlsSet.contains(key)) {
+ if ("/login/signin".equals(requestUri)) {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ User user = mapper.readValue(request.getInputStream(), User.class);
+ String username = user.getUsername();
+ String password = user.getPassword();
+ User resultUser = userApi.signin(user);
+ if (resultUser != null && resultUser.getToken() != null) {
+ sendResponse(200, "{\"token\": \"" + resultUser.getToken() + "\"}");
+ } else {
+ sendResponse(401, "cannot sign in!");
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ sendResponse(401, e.getMessage());
+ }
+ }
+ return null;
+ } else {
+ sendResponse(401, "the request url is not validate");
+ }
+ return null;
+
+ }
+
+ private void sendResponse(int code, String message) {
+ ctx.setSendZuulResponse(false);
+ ctx.setResponseStatusCode(code);
+ try {
+ ctx.getResponse().getWriter().write(message);
+ } catch (Exception e) {
+ log.warn(e.getMessage());
+ }
+ }
+
+
+}
diff --git a/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/rpc/UserApi.java b/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/rpc/UserApi.java
new file mode 100755
index 0000000..3a82676
--- /dev/null
+++ b/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/rpc/UserApi.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.gateway.rpc;
+
+import org.apache.servicecomb.samples.practise.houserush.gateway.rpc.po.User;
+
+public interface UserApi {
+ User signin(User user);
+
+ User verifyToken(String token);
+}
diff --git a/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/rpc/po/User.java b/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/rpc/po/User.java
new file mode 100755
index 0000000..5b37356
--- /dev/null
+++ b/houserush/gateway/src/main/java/org/apache/servicecomb/samples/practise/houserush/gateway/rpc/po/User.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.gateway.rpc.po;
+
+import lombok.Data;
+
+@Data
+public class User {
+ private int id;
+ private String username;
+ private String password;
+ private String token;
+}
diff --git a/houserush/gateway/src/main/resources/application.yaml b/houserush/gateway/src/main/resources/application.yaml
new file mode 100755
index 0000000..c46bf3e
--- /dev/null
+++ b/houserush/gateway/src/main/resources/application.yaml
@@ -0,0 +1,39 @@
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements. See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License. You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+
+zuul:
+ routes:
+ realestate: /realestate/**
+ customer-manage: /customer-manage/**
+ house-order: /house-order/**
+ login: /login/**
+ user-center: /user-center/**
+
+
+
+# disable netflix eurkea since it's not used for service discovery
+ribbon:
+ eureka:
+ enabled: false
+
+server:
+ port: 8889
+
+servicecomb:
+ tracing:
+ enabled: false
+
diff --git a/houserush/gateway/src/main/resources/microservice.yaml b/houserush/gateway/src/main/resources/microservice.yaml
new file mode 100755
index 0000000..2f44af2
--- /dev/null
+++ b/houserush/gateway/src/main/resources/microservice.yaml
@@ -0,0 +1,66 @@
+#
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements. See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License. You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+
+# all interconnected microservices must belong to an application wth the same ID
+APPLICATION_ID: houserush
+service_description:
+ # name of the declaring microservice
+ name: gateway
+ version: 0.0.4
+servicecomb:
+ service:
+ registry:
+ address: http://127.0.0.1:30100
+
+gateway:
+ loginUrls:
+ - POST /realestate/realestates
+ - GET /realestate/realestates/{id}
+ - PUT /realestate/realestates/{id}
+ - DELETE /realestate/realestates/{id}
+ - GET /realestate/realestates
+ - POST /realestate/{id}/buildings
+ - GET /realestate/buildings/{id}
+ - PUT /realestate/buildings/{id}
+ - DELETE /realestate/buildings/{id}
+ - GET /realestate/realestates/{id}/buildings
+ - POST /realestate/buildings/{buildingId}/houses
+ - GET /realestate/houses/{id}
+ - PUT /realestate/houses/{id}
+ - DELETE /realestate/houses/{id}
+ - GET /realestate/buildings/{id}/houses
+ - PUT /realestate/houses/lock_houses_for_sale
+ - POST /customer-manage/customers
+ - GET /customer-manage/customers/{id}
+ - PUT /customer-manage/customers/{id}
+ - DELETE /customer-manage/customers/{id}
+ - GET /customer-manage/customers
+ - PUT /customer-manage/customers/{id}/update_qualifications
+ - POST /house-order/sales/{id}/house_orders
+ - PUT /house-order/house_orders/{id}
+ - POST /house-order/sales
+ - GET /house-order/sales/{id}
+ - PUT /house-order/sales/{id}
+ - DELETE /house-order/sales/{id}
+ - GET /house-order/sales
+
+
+ noLoginUrls:
+ - POST /login/users
+ - PUT /login/signin
+
diff --git a/houserush/login/README.md b/houserush/login/README.md
new file mode 100755
index 0000000..efbe99d
--- /dev/null
+++ b/houserush/login/README.md
@@ -0,0 +1,89 @@
+## 微服务 login
+
+该微服务作为认证中心,主要负责token的生成与校验。
+
+### 主要功能
+
+- 登录账号的维护
+
+- 生成token
+
+- 校验token
+
+### 设计原理
+
+基于[JWT](https://jwt.io/introduction/)实现易于横向拓展的分布式认证中心。
+
+JWT标准格式
+
+```json
+{
+ //Header
+ "alg": "HS256",
+ "typ": "JWT",
+ //Payload
+ "sub": "1234567890",
+ "name": "John Doe",
+ "admin": true,
+ //Signature
+ HMACSHA256(
+ base64UrlEncode(header) + "." +
+ base64UrlEncode(payload),
+ secret)
+}
+```
+
+[JWT的一种实现](https://github.com/auth0/java-jwt)
+
+
+
+### 数据库设计
+
+users表
+
+| id | int | 主键id |
+| :-------------- | ------------ | -------- |
+| username | varchar(255) | 用户名 |
+| hashed_password | varchar(255) | 密码hash |
+| deleted_at | timestamp | 删除时间 |
+| created_at | timestamp | 创建时间 |
+| update_at | timestamp | 更新时间 |
+
+##### 聚合
+
+user
+
+```java
+class User{
+
+ //对密码hash加密
+ String makeHashedPassword(){};
+
+ //使用auth0的java-jwt库来生成jwt
+ String generateToken() {};
+
+ //解密token获取Id
+ int verifyTokenGetUserId(){};
+}
+```
+
+
+
+### 接口设计
+
+```java
+ User createUser(User user);
+
+ User findUser(int id);
+
+ void removeUser(int id);
+
+ boolean updatePassword(int id,String oldPassword,String newPassword)
+
+ //登录,签发token
+ User signin(User user);
+
+ //校验token
+ User verifyToken(String token);
+```
+
diff --git a/houserush/login/pom.xml b/houserush/login/pom.xml
index a1965ab..5d32776 100644
--- a/houserush/login/pom.xml
+++ b/houserush/login/pom.xml
@@ -61,6 +61,11 @@
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.auth0</groupId>
+ <artifactId>java-jwt</artifactId>
+ <version>3.8.1</version>
+ </dependency>
</dependencies>
<build>
diff --git a/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/LoginApplication.java b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/LoginApplication.java
new file mode 100755
index 0000000..be12850
--- /dev/null
+++ b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/LoginApplication.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.login;
+
+import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import java.text.SimpleDateFormat;
+import java.util.TimeZone;
+
+@SpringBootApplication
+@EnableServiceComb
+@EnableJpaAuditing
+public class LoginApplication {
+
+ public static void main(String[] args) {
+ configBeforeBoot();
+ SpringApplication.run(LoginApplication.class, args);
+ }
+
+ private static void configBeforeBoot() {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
+ RestObjectMapperFactory.getRestObjectMapper().setDateFormat(simpleDateFormat);
+ }
+}
diff --git a/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/LoginConfig.java b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/LoginConfig.java
new file mode 100755
index 0000000..03bc4a7
--- /dev/null
+++ b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/LoginConfig.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.login;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+
+@Configuration
+@EnableJpaRepositories(basePackages = "org.apache.servicecomb.samples.practise.houserush")
+public class LoginConfig {
+}
diff --git a/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/aggregate/User.java b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/aggregate/User.java
new file mode 100755
index 0000000..c36db7c
--- /dev/null
+++ b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/aggregate/User.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.login.aggregate;
+
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.interfaces.JWTVerifier;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+import org.apache.commons.lang.StringUtils;
+import org.hibernate.annotations.SQLDelete;
+import org.hibernate.annotations.Where;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.persistence.*;
+import java.util.Base64;
+import java.util.Calendar;
+import java.util.Date;
+
+@Data
+@Entity
+@Table(name = "users")
+@SQLDelete(sql = "update users set deleted_at = now() where id = ?")
+@Where(clause = "deleted_at is null")
+@EntityListeners(AuditingEntityListener.class)
+public class User {
+ private final static String USER_SECRET = "231sdfqwer21313123cafkhioerutieweirqwuqbjffbqwrwr3";
+ private final static String HASH_TYPE = "HmacSHA256";
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Integer id;
+
+ private String username;
+
+ @Transient
+ private String password;
+
+ @Transient
+ private String oldPassword;
+
+ @JsonIgnore
+ private String hashedPassword;
+
+ @Temporal(TemporalType.TIMESTAMP)
+ private Date deletedAt;
+
+ @CreatedDate
+ @Temporal(TemporalType.TIMESTAMP)
+ private Date createdAt;
+
+ @LastModifiedDate
+ @Temporal(TemporalType.TIMESTAMP)
+ private Date updatedAt;
+
+ @Transient
+ private String token;
+
+
+ public String makeHashedPassword(String password) {
+ try {
+ String data = username + password;
+ SecretKey secretKey = new SecretKeySpec(USER_SECRET.getBytes(), HASH_TYPE);
+ Mac mac = Mac.getInstance(HASH_TYPE);
+ mac.init(secretKey);
+ byte[] bytes = mac.doFinal(data.getBytes());
+ return new String(Base64.getEncoder().encode(bytes));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String generateToken() {
+ Calendar calendar = Calendar.getInstance();
+ calendar.add(Calendar.MINUTE, 30);
+ Algorithm algorithm = Algorithm.HMAC256(USER_SECRET);
+ token = JWT.create().withSubject(String.valueOf(id)).withExpiresAt(calendar.getTime()).sign(algorithm);
+ return token;
+ }
+
+ private static Algorithm algorithm = null;
+ private static JWTVerifier verifier = null;
+
+ {
+ algorithm = Algorithm.HMAC256(USER_SECRET);
+ verifier = JWT.require(algorithm)
+ .build();
+ }
+
+ public static int verifyTokenGetUserId(String token) {
+ String sub = verifier.verify(token).getSubject();
+ if (StringUtils.isNotBlank(sub)) {
+ return Integer.parseInt(sub);
+ }
+ throw new RuntimeException("verify the token fails");
+ }
+}
diff --git a/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/api/UserApi.java b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/api/UserApi.java
new file mode 100755
index 0000000..c64d0f9
--- /dev/null
+++ b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/api/UserApi.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.login.api;
+
+import org.apache.servicecomb.samples.practise.houserush.login.aggregate.User;
+
+public interface UserApi {
+ User createUser(User user);
+
+ User findUser(int id);
+
+ void removeUser(int id);
+
+ User signin(User user);
+
+ User verifyToken(String token);
+
+ boolean updatePassword(int customerId, User user);
+}
diff --git a/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/api/UserApiRestImpl.java b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/api/UserApiRestImpl.java
new file mode 100755
index 0000000..25203d0
--- /dev/null
+++ b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/api/UserApiRestImpl.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.login.api;
+
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.apache.servicecomb.samples.practise.houserush.login.aggregate.User;
+import org.apache.servicecomb.samples.practise.houserush.login.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestSchema(schemaId = "userApiRest")
+@RequestMapping("/")
+public class UserApiRestImpl implements UserApi {
+ @Autowired
+ UserService userService;
+
+ @PostMapping("users")
+ public User createUser(@RequestBody User user) {
+ return userService.createUser(user);
+ }
+
+ @GetMapping("users/{id}")
+ public User findUser(@PathVariable int id) {
+ return userService.findUser(id);
+ }
+
+ @DeleteMapping("users/{id}")
+ public void removeUser(@PathVariable int id) {
+ userService.removeUser(id);
+ }
+
+ @PutMapping("users/signin")
+ public User signin(@RequestBody User user) {
+ return userService.signin(user);
+ }
+
+ @PutMapping("users/verify_token")
+ public User verifyToken(@RequestParam String token) {
+ return userService.verifyToken(token);
+ }
+
+ @PutMapping("users/password")
+ public boolean updatePassword(@RequestHeader int customerId, @RequestBody User user) {
+ return userService.updatePassword(customerId, user.getOldPassword(), user.getPassword());
+ }
+}
diff --git a/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/dao/UserDao.java b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/dao/UserDao.java
new file mode 100755
index 0000000..a13807e
--- /dev/null
+++ b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/dao/UserDao.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.login.dao;
+
+import org.apache.servicecomb.samples.practise.houserush.login.aggregate.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface UserDao extends JpaRepository<User, Integer> {
+ User findByUsername(String username);
+}
diff --git a/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/service/UserService.java b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/service/UserService.java
new file mode 100755
index 0000000..cec944c
--- /dev/null
+++ b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/service/UserService.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.login.service;
+
+import org.apache.servicecomb.samples.practise.houserush.login.aggregate.User;
+
+public interface UserService {
+ User createUser(User user);
+
+ User findUser(int id);
+
+ User updateUser(User user);
+
+ void removeUser(int id);
+
+ User signin(User user);
+
+ User verifyToken(String token);
+
+ boolean updatePassword(int id, String oldPassword, String newPassword);
+}
diff --git a/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/service/UserServiceImpl.java b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/service/UserServiceImpl.java
new file mode 100755
index 0000000..409fe94
--- /dev/null
+++ b/houserush/login/src/main/java/org/apache/servicecomb/samples/practise/houserush/login/service/UserServiceImpl.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.samples.practise.houserush.login.service;
+
+import org.apache.servicecomb.samples.practise.houserush.login.aggregate.User;
+import org.apache.servicecomb.samples.practise.houserush.login.dao.UserDao;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataRetrievalFailureException;
+import org.springframework.stereotype.Service;
+
+@Service
+public class UserServiceImpl implements UserService {
+
+ @Autowired
+ UserDao userDao;
+
+ public User createUser(User user) {
+ if (userDao.findByUsername(user.getUsername()) != null) {
+ throw new InvocationException(400, "", "用户名已存在");
+ }
+ String hashedPassword = user.makeHashedPassword(user.getPassword());
+ user.setHashedPassword(hashedPassword);
+ return userDao.save(user);
+ }
+
+
+ public User findUser(int id) {
+ return userDao.findOne(id);
+ }
+
+ public User updateUser(User user) {
+ int id = user.getId();
+ if (userDao.exists(id)) {
+ return userDao.save(user);
+ } else {
+ throw new DataRetrievalFailureException("cannot update non-existed user");
+ }
+ }
+
+ public void removeUser(int id) {
+ userDao.delete(id);
+ }
+
+ public User signin(User user) {
+ String username = user.getUsername();
+ String password = user.getPassword();
+ user = userDao.findByUsername(username);
+ if (user != null && password != null) {
+ if (user.getHashedPassword().equals(user.makeHashedPassword(password))) {
+ user.generateToken();
+ return user;
+ }
+ }
+ return null;
+ }
+
+ public User verifyToken(String token) {
+ int userId = User.verifyTokenGetUserId(token);
+ User user = userDao.findOne(userId);
+ user.generateToken();
+ return user;
+ }
+
+ @Override
+ public boolean updatePassword(int id, String oldPassword, String newPassword) {
+ User user = userDao.findOne(id);
+ if (user == null) {
+ throw new InvocationException(400, "", "user not existed");
+ }
+ if (!user.getHashedPassword().equals(user.makeHashedPassword(oldPassword))) {
+ throw new InvocationException(400, "", "The password is incorrect");
+ }
+ user.setHashedPassword(user.makeHashedPassword(newPassword));
+ userDao.save(user);
+ return true;
+ }
+}
diff --git a/houserush/login/src/main/resources/microservice.yaml b/houserush/login/src/main/resources/microservice.yaml
new file mode 100755
index 0000000..e8e6cd2
--- /dev/null
+++ b/houserush/login/src/main/resources/microservice.yaml
@@ -0,0 +1,43 @@
+#
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements. See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License. You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+
+# all interconnected microservices must belong to an application wth the same ID
+APPLICATION_ID: houserush
+service_description:
+ # name of the declaring microservice
+ name: login
+ version: 0.0.10
+servicecomb:
+ service:
+ registry:
+ address: http://127.0.0.1:30100
+ rest:
+ address: 0.0.0.0:6777
+ handler:
+ chain:
+ Provider:
+ default: bizkeeper-provider
+spring:
+ datasource:
+ url: jdbc:mysql://127.0.0.1:3306/login?characterEncoding=utf8&useSSL=false
+ username: root
+ password: root
+ jpa:
+ properties:
+ hibernate:
+ enable_lazy_load_no_trans: true
\ No newline at end of file