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 <[email protected]> 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网关功能 + + + +### 实现 + +- 路由转发配置 + +- 鉴权 + + - 自定义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
