Commit 321ba575 authored by hubin's avatar hubin

初始化仓库

parents
# Created by .ignore support plugin (hsz.mobi)
### Java template
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
.idea
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
*/target
**/target
*.iml
stages:
- name: compile
steps:
- runScriptConfig:
image: localhost:9999/library/maven-build-tool
shellScript: mvn -version
timeout: 60
notification: {}
![](https://img.shields.io/badge/ism--services-v1.0.0-blue)
![](https://img.shields.io/badge/SpringBoot-2.3.2-brightgreen.svg)
![](https://img.shields.io/badge/SpringCloud-Hoxton.SR8-green.svg)
## 项目说明
> 1. 依赖环境说明
> [](https://img.shields.io/badge/Rancher、k8s、docker-green)
>
> 项目环境,部署在`121.5.28.27`
>
> ![](https://img.shields.io/badge/harbor-green)
>
> docker镜像仓库,使用`docker`部署在`121.5.28.27` 用户名:`admin`密码:`Hg123harbor`
>
> ![](https://img.shields.io/badge/nexus-green)
>
> maven仓库,使用`docker`部署在`121.5.28.27` 用户名:`admin`密码:`Hg123nexus`
>
> ![](https://img.shields.io/badge/jenkins-green)
>
> 自动化部署,使用`docker`部署在`121.5.28.27` 用户名:`admin`密码:`Hg123jenkins`
>
> ![](https://img.shields.io/badge/nacos-green)
>
> 用于服务注册与配置中心,部署砸`Rancher`中
>
> ![](https://img.shields.io/badge/mysql-green)
>
> 项目数据库,使用`docker`部署在`129.211.99.254`,数据库:`qywchat`用户名:`dev`密码:`Hgdev#012Qw`
>
> ![](https://img.shields.io/badge/redis-green)
>
> 项目缓存数据,使用`docker`部署在`129.211.99.254` 密码:`Hgdevreids#012Qw`s
> 2. 工程说明
>
> `auth` 鉴权中心
>
> `common` 常用包的父类 打成jar包给到其他项目引用
>
> `common-core` 工具类和pojo写在该工程下 打成jar包给到其他项目引用
>
> `common-mybatis` mybatis的依赖 打成jar包给到其他项目引用
>
> `common-redis` redis的依赖 打成jar包给到其他项目引用
>
> `gateway` 网关
>
> `system` 系统服务
>
> `system-api` 系统服务提供费feign API,打成jar包给到其他需要使用系统服务的项目引用
>
> `system-user-service` 系统服务的业务代码,
>3.部署说明
>
> 1) 如果是增加了服务,请在服务根目录新增`DOCKERFILE`和`deployment.yaml`文件,可参考`gateway`和`auth`服务,
> 并且在主项目根目录的`build.sh`增加服务的构建工作
> 2) 如果是增加服务`api`的依赖jar包,请参考`common-core`、`common-mybatis`、`system-api`等子项目,
> 并且在主项目根目录的`build.sh`增加将jar包提交远程仓库的操作(在`buildDeploys`中加入路径即可)
#指定依赖的镜像
FROM localhost:9999/library/java:8
#springboot
VOLUME /tmp
#容器使用端口
EXPOSE 8000
#添加jar包入容器
ADD auth-service/target/auth-0.0.1.jar app.jar
#改名
RUN sh -c 'touch /app.jar'
#容器启动java
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
apiVersion: apps/v1
kind: Deployment
metadata:
name: ism-auth-service
namespace: ism-service
labels:
app: ism-auth-service
spec:
replicas: 1
selector:
matchLabels:
app: ism-auth-service
template:
metadata:
labels:
app: ism-auth-service
spec:
imagePullSecrets:
- name: ism-harbor
containers:
- name: ism-auth-service #TODO:pod的名称,必须字段,名称唯一且对象创建后不可以被修改
image: localhost:9999/ism/ism-auth-service:latest #TODO:镜像仓库的路径/镜像的名称:镜像的标签,
imagePullPolicy: Always #Always(总是去仓库下载),Never(从不去仓库下载),IfNotPresent(如果本地没有就去仓库下载),默认是"IfNotPresent"
ports:
- containerPort: 8001 #TODO:containerPort是pod内部容器的端口,targetPort映射到containerPort;例如,mysql服务需要暴露3306端口,redis暴露6379端口
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ism</artifactId>
<groupId>com.hungraim.ism</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>auth</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--基础配置数据源-->
<dependency>
<groupId>com.hungraim.ism</groupId>
<artifactId>common-core</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>com.hungraim.ism</groupId>
<artifactId>common-mybatis</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>com.hungraim.ism</groupId>
<artifactId>common-redis</artifactId>
<version>0.0.1</version>
</dependency>
<!--基础配置数据源-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-nacos-config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!--feign服务调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--系统服务api-->
<dependency>
<groupId>com.hungraim.ism</groupId>
<artifactId>system-api</artifactId>
<version>0.0.1</version>
</dependency>
<!--微信服务api-->
<dependency>
<groupId>com.hungraim.ism</groupId>
<artifactId>wechat-api</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Oauth2相关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<!--Oauth2相关依赖 end-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!--重要-->
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.hungraim.ism;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* @author hubin
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class AuthApplication {
public static void main(String[] args) {
SpringApplication.run(AuthApplication.class, args);
}
}
package com.hungraim.ism.controller;
import com.hungraim.ism.util.RequestUtils;
import com.hungraim.ism.util.Result;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.web.bind.annotation.*;
import java.security.Principal;
import java.util.Map;
/**
* 认证中心
*
* @author hubin
*/
@RestController
@RequestMapping("/oauth")
@AllArgsConstructor
public class AuthController {
private final TokenEndpoint tokenEndpoint;
@PostMapping("/token")
@SneakyThrows
public Result<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) {
OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
return Result.success(oAuth2AccessToken);
}
}
package com.hungraim.ism.controller;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.KeyPair;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
/**
* @author hubin
*/
@RestController
@RequestMapping
@AllArgsConstructor
@Slf4j
public class PublicKeyController {
private final KeyPair keyPair;
@GetMapping("/getPublicKey")
public Map<String, Object> loadPublicKey() {
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAKey key = new RSAKey.Builder(publicKey).build();
return new JWKSet(key).toJSONObject();
}
}
package com.hungraim.ism.gateway.config;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONUtil;
import com.hungraim.ism.api.WechatFeignService;
import com.hungraim.ism.gateway.config.tokenGranters.EnterpriseWechatTokenGranter;
import com.hungraim.ism.pojo.vo.system.UserLoginInfoVO;
import com.hungraim.ism.service.UserDetailsServiceImpl;
import com.hungraim.ism.util.Result;
import com.hungraim.ism.util.ResultCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenGranter;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeTokenGranter;
import org.springframework.security.oauth2.provider.implicit.ImplicitTokenGranter;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.security.oauth2.provider.refresh.RefreshTokenGranter;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.sql.DataSource;
import java.security.KeyPair;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 认证服务配置
*
* @author hubin
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final UserDetailsServiceImpl userDetailsService;
private final DataSource dataSource;
private final WechatFeignService wechatFeignService;
@Autowired
public AuthorizationServerConfiguration(AuthenticationManager authenticationManager, DataSource dataSource, UserDetailsServiceImpl userDetailsService, WechatFeignService wechatFeignService) {
this.authenticationManager = authenticationManager;
this.dataSource = dataSource;
this.userDetailsService = userDetailsService;
this.wechatFeignService = wechatFeignService;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetails());
}
/**
* 通过配置JDBC获取客户端信息
*/
@Bean
public ClientDetailsService clientDetails() {
return new JdbcClientDetailsService(dataSource);
}
/**
* 配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services)
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
tokenEnhancers.add(tokenEnhancer());
tokenEnhancers.add(jwtAccessTokenConverter());
tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
endpoints
.authenticationManager(authenticationManager)
.accessTokenConverter(jwtAccessTokenConverter())
.tokenEnhancer(tokenEnhancerChain)
.userDetailsService(userDetailsService)
.tokenGranter(tokenGranter(endpoints))
// refresh token有两种使用方式:重复使用(true)、非重复使用(false),默认为true
// 1 重复使用:access token过期刷新时, refresh token过期时间未改变,仍以初次生成的时间为准
// 2 非重复使用:access token过期刷新时, refresh token过期时间延续,在refresh token有效期内刷新便永不失效达到无需再次登录的目的
.reuseRefreshTokens(true);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security.authenticationEntryPoint(authenticationEntryPoint()).passwordEncoder(new BCryptPasswordEncoder())
.tokenKeyAccess("isAuthenticated()")
.checkTokenAccess("permitAll()")
.allowFormAuthenticationForClients();
}
private TokenGranter tokenGranter(AuthorizationServerEndpointsConfigurer endpoints) {
List<TokenGranter> list = new ArrayList<>();
// 这里配置密码模式
if (authenticationManager != null) {
list.add(new ResourceOwnerPasswordTokenGranter(authenticationManager,
endpoints.getTokenServices(),
endpoints.getClientDetailsService(),
endpoints.getOAuth2RequestFactory()));
}
//刷新token模式、
list.add(new RefreshTokenGranter
(endpoints.getTokenServices(),
endpoints.getClientDetailsService(),
endpoints.getOAuth2RequestFactory()));
//授权码模式、
list.add(new AuthorizationCodeTokenGranter(
endpoints.getTokenServices(),
endpoints.getAuthorizationCodeServices(),
endpoints.getClientDetailsService(),
endpoints.getOAuth2RequestFactory()));
//、简化模式
list.add(new ImplicitTokenGranter(
endpoints.getTokenServices(),
endpoints.getClientDetailsService(),
endpoints.getOAuth2RequestFactory()));
//客户端模式
list.add(new ClientCredentialsTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
list.add(new EnterpriseWechatTokenGranter(
endpoints.getTokenServices(),
endpoints.getClientDetailsService(),
endpoints.getOAuth2RequestFactory(),
wechatFeignService));
return new CompositeTokenGranter(list);
}
/**
* 自定义认证异常响应数据
*/
@Bean
public AuthenticationEntryPoint authenticationEntryPoint() {
return (request, response, e) -> {
response.setStatus(HttpStatus.HTTP_OK);
response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().print(JSONUtil.toJsonStr(Result.failed(ResultCode.CLIENT_AUTHENTICATION_FAILED)));
response.getWriter().flush();
};
}
/**
* 使用非对称加密算法对token签名
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setKeyPair(keyPair());
return converter;
}
/**
* 从classpath下的密钥库中获取密钥对(公钥+私钥)
*/
@Bean
public KeyPair keyPair() {
KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
new ClassPathResource("ism.jks"), "Hg123ism".toCharArray());
return factory.getKeyPair(
"ism", "Hg123ism".toCharArray());
}
@Bean
public TokenEnhancer tokenEnhancer() {
return (accessToken, authentication) -> {
UserLoginInfoVO user = (UserLoginInfoVO) authentication.getUserAuthentication().getPrincipal();
Map<String, Object> map = new HashMap<>(4);
map.put("name", user.getName());
map.put("avatar", user.getAvatar());
map.put("userId", user.getUserId());
map.put("account", user.getUsername());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(map);
return accessToken;
};
}
}
package com.hungraim.ism.gateway.config;
import com.hungraim.ism.util.Result;
import com.hungraim.ism.util.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 异常全局处理
* @author hubin
*/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 身份验证异常
* @param e 异常实例
* @return 返回信息
*/
@ExceptionHandler(AuthenticationException.class)
@ResponseBody
public Result<Exception> authenticationExceptionHandler(AuthenticationException e){
log.warn("authenticationExceptionHandler:{}",e.getMessage());
return Result.failed();
}
/**
* OAUTH2身份验证异常
* @param e 异常实例
* @return 返回信息
*/
@ExceptionHandler(OAuth2Exception.class)
@ResponseBody
public Result<Exception> oAuth2ExceptionHandle(OAuth2Exception e){
log.warn("oAuth2ExceptionHandler:{}",e.getMessage());
if(e instanceof InvalidGrantException){
return Result.failed(ResultCode.USERNAME_OR_PASSWORD_ERROR);
}
return Result.failed(e.getMessage());
}
}
package com.hungraim.ism.gateway.config;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author hubin
*/
@Configuration
@EnableWebSecurity
@Order(1)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() //关闭csrf保护
.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
.and()
.authorizeRequests()
.antMatchers("/getPublicKey","/oauth/logout").permitAll()
.anyRequest().authenticated();
}
/**
* 如果不配置SpringBoot会自动配置一个AuthenticationManager,覆盖掉内存中的用户
*/
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
package com.hungraim.ism.gateway.config.tokenGranters;
import com.hungraim.ism.api.WechatFeignService;
import com.hungraim.ism.pojo.entity.system.SystemUser;
import com.hungraim.ism.pojo.vo.system.UserLoginInfoVO;
import com.hungraim.ism.util.Result;
import com.hungraim.ism.util.ResultCode;
import org.springframework.security.core.Authentication;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 自定义grant_type模式--企业微信认证
* @author hubin
*/
public class EnterpriseWechatTokenGranter extends AbstractTokenGranter {
private static final String GRANT_TYPE = "enterpriseWechat";
private final WechatFeignService wechatFeignService;
public EnterpriseWechatTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory oAuth2RequestFactory, WechatFeignService wechatFeignService) {
super(tokenServices,clientDetailsService,oAuth2RequestFactory,GRANT_TYPE);
this.wechatFeignService = wechatFeignService;
}
@SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")
@Override
protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
String code = parameters.get("code");
//通过code去企业微信获取用户id 再组装成用户
Result<SystemUser> user = wechatFeignService.getUserInfoByCode(code);
if(user==null || !ResultCode.SUCCESS.getCode().equals(user.getCode())){
throw new InvalidGrantException(user.getMsg());
}
UserDetails userDTO = new UserLoginInfoVO(user.getData());
Authentication userAuth = new UsernamePasswordAuthenticationToken(userDTO, null, userDTO.getAuthorities());
return new OAuth2Authentication( getRequestFactory().createOAuth2Request(client, tokenRequest), userAuth);
}
}
package com.hungraim.ism.service;
import com.hungraim.ism.api.SystemUserFeignService;
import com.hungraim.ism.pojo.entity.system.SystemMarketer;
import com.hungraim.ism.pojo.entity.system.SystemUser;
import com.hungraim.ism.pojo.vo.system.UserLoginInfoVO;
import com.hungraim.ism.util.Result;
import com.hungraim.ism.util.ResultCode;
import lombok.AllArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author hubin
*/
@Service
@AllArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
private final SystemUserFeignService systemUserFeignService;
@Override
public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {
//获取用户基本信息
Result<SystemUser> userRes = systemUserFeignService.loadUserInfoByAccount(account);
//用户不存在
if (ResultCode.USER_NOT_EXIST.getCode().equals(userRes.getCode())) {
throw new UsernameNotFoundException(ResultCode.USER_NOT_EXIST.getMsg());
}
SystemUser systemUser = userRes.getData();
//根据用户id获取用户权限
Result<List<Long>> roles = systemUserFeignService.loadUserRolesByUserId(systemUser.getId());
UserLoginInfoVO userLoginInfoVO = new UserLoginInfoVO(systemUser);
userLoginInfoVO.setAuthorities(roles.getData());
Result<SystemMarketer> systemMarketerRes = systemUserFeignService.loadUserDetailByCode(systemUser.getMarketerCode());
if (!ResultCode.MARKETER_NOT_EXIST.getCode().equals(systemMarketerRes.getCode())) {
SystemMarketer systemMarketer = systemMarketerRes.getData();
userLoginInfoVO.setAvatar(systemMarketer.getAvatar());
}
return userLoginInfoVO;
}
}
spring:
devtools:
restart:
enabled: true
additional-paths: src/main/java
application:
name: ISM-AUTH-SERVICE
cloud:
nacos:
discovery:
server-addr: qw.hungraim.com:31158
namespace: 74494ee6-1c9c-4165-97d2-d876f4b4befc
config:
namespace: 74494ee6-1c9c-4165-97d2-d876f4b4befc
server-addr: qw.hungraim.com:31158
file-extension: yaml # 必须修改成yaml
extension-configs:
- data-id: ism-auth.yaml
group: auth
refresh: true
- data-id: ism-database.yaml
group: common
refresh: true
- data-id: ism-basic.yaml
group: common
refresh: true
server:
port: 8000
#!/bin/bash
echo '开始构建智能营销平台项目'
export PATH=${PATH}:/usr/local/maven/bin
buildDeploys=("common/common-core" "common/common-mybatis" "common/common-redis" "system/system-api" "wechat/wechat-api")
mvn clean #清空历史数据
buildDeploy(){
for ((i=0;i<${#buildDeploys[*]};i++))
do
nProject=${buildDeploys[i]}
echo "开始处理${nProject}"
cd "${WORKSPACE}"/"${nProject}"
mvn deploy
done
echo "静态依赖处理完毕,准备开始构建服务。。。"
}
buildDeploy
cd "${WORKSPACE}"
mvn install
kubectl delete deployment ism-auth-service -n ism-service
kubectl delete deployment ism-gateway-service -n ism-service
kubectl delete deployment ism-system-user-service -n ism-service
kubectl delete deployment ism-system-label-service -n ism-service
kubectl delete deployment ism-system-clue-service -n ism-service
kubectl delete deployment ism-wechat-service -n ism-service
docker images | grep -E "(ism)" | awk '{print $3}' | uniq | xargs -I {} docker rmi --force {}
echo "服务构建完毕,开始打包docker镜像..."
docker login -u admin -p Hg123harbor localhost:9999
echo "==================auth镜像==================="
docker build -t localhost:9999/ism/ism-auth-service:latest -f auth-service/DOCKERFILE .
docker push localhost:9999/ism/ism-auth-service:latest
echo "==================gateway镜像==================="
docker build -t localhost:9999/ism/ism-gateway-service:latest -f gateway-service/DOCKERFILE .
docker push localhost:9999/ism/ism-gateway-service:latest
echo "==================system-user-service镜像==================="
docker build -t localhost:9999/ism/ism-system-user-service:latest -f system/system-user-service/DOCKERFILE .
docker push localhost:9999/ism/ism-system-user-service:latest
echo "==================system-clue-service镜像==================="
docker build -t localhost:9999/ism/system-clue-service:latest -f system/system-clue-service/DOCKERFILE .
docker push localhost:9999/ism/system-clue-service:latest
echo "==================system-label-service镜像==================="
docker build -t localhost:9999/ism/system-label-service:latest -f system/system-label-service/DOCKERFILE .
docker push localhost:9999/ism/system-label-service:latest
echo "==================wechat-service镜像==================="
docker build -t localhost:9999/ism/ism-wechat-service:latest -f wechat/wechat-service/DOCKERFILE .
docker push localhost:9999/ism/ism-wechat-user-service:latest
echo "docker镜像上传完毕,智能营销平台项目构建完毕"
echo "清理缓存。。。"
mvn clean
echo "开始部署k8s服务..."
echo "===========auth-service=============="
kubectl create -f ./auth-service/deployment.yaml
echo "===========gateway-service=============="
kubectl create -f ./gateway-service/deployment.yaml
echo "===========user-service=============="
kubectl create -f ./system/system-user-service/deployment.yaml
echo "===========label-service=============="
kubectl create -f ./system/system-label-service/deployment.yaml
echo "===========clue-service=============="
kubectl create -f ./system/system-clue-service/deployment.yaml
echo "===========wechat-service=============="
kubectl create -f ./wechat/wechat-service/deployment.yaml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>com.hungraim.ism</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-core</artifactId>
<dependencies>
<dependency>
<groupId>com.hungraim.ism</groupId>
<artifactId>common-redis</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
<distributionManagement>
<repository>
<id>releases</id>
<name>Nexus Release Repository</name>
<url>http://121.5.28.27:9091/nexus/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>http://121.5.28.27:9091/nexus/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
package com.hungraim.ism.constant;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
/**
*
* 线索分配状态
* @author hubin
*/
@NoArgsConstructor
@AllArgsConstructor
public enum AssignStatus {
//分配情况
ASSIGNED("1", "已分配"),
UNASSIGNED("0", "未分配");
/**
* 编码
*/
private String code;
/**
* 描述
*/
private String desc;
public String getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
package com.hungraim.ism.constant;
/**
* @author hubin
*/
public interface AuthConstants {
/**
* 认证请求头key
*/
String AUTHORIZATION_KEY = "Authorization";
/**
* JWT令牌前缀
*/
String JWT_PREFIX = "bearer ";
/**
* Basic认证前缀
*/
String BASIC_PREFIX = "Basic ";
/**
* JWT载体key
*/
String JWT_PAYLOAD_KEY = "payload";
/**
* Redis缓存权限规则key
*/
String PERMISSION_ROLES_KEY = "ism:auth:permission:roles";
/**
* 密码加密方式
*/
String BCRYPT = "{bcrypt}";
String JWT_USER_ID_KEY = "user_id";
String CLIENT_ID_KEY = "client_id";
/**
* JWT存储权限前缀
*/
String AUTHORITY_PREFIX = "ROLE_";
/**
* JWT存储权限属性
*/
String JWT_AUTHORITIES_KEY = "authorities";
/**
* JWT存储权限属性
*/
String RESOURCE_ROLE_KEY = "resource_role";
/**
* 后台管理服务路径
*/
String ADMIN_URL_PATTERN = "*_/api.system/**";
}
package com.hungraim.ism.constant;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
/**
* 性别
* @author hubin
*/
@AllArgsConstructor
@NoArgsConstructor
public enum Gender {
//男
MAN("1", "男"),
//女
WOMAN("2", "女");
/**
* 编码
*/
private String code;
/**
* 描述
*/
private String desc;
public String getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
package com.hungraim.ism.constant;
/**
* @author hubin
*/
public interface WechatConstants {
/**
* 获取access_token接口地址
*/
String GET_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
String GET_USERID_FRO_CODE_URL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo";
String GET_MOBILE_HASHCODE_URL = "https://qyapi.weixin.qq.com/cgi-bin/user/get_mobile_hashcode";
String WECHAT_REDIS_KEY = "ism:system:wechat";
String ACCESS_TOKEN_REDIS_KEY = "accessToken";
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
*
* 机构表
* @author hubin
*/
@Data
@TableName("ISM_AGENCY")
public class SystemAgency {
private int id;
private String agencyCode;
private String agencyName;
private String enable;
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* 地区表
*
* @author jiaguokai
*/
@Data
@TableName("ISM_AREA")
public class SystemArea {
private int id;
private String areaCode;
private String areaName;
private String cityCode;
private String enable;
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* 城市表
*
* @author jiaguokai
*/
@Data
@TableName("ISM_CITY")
public class SystemCity {
private int id;
private String cityCode;
private String cityName;
private String provinceCode;
private String enable;
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* @author hubin
*/
@Data
@TableName("oauth_client_details")
public class SystemClientDetails {
private String clientId;
private String resourceIds;
private String clientSecret;
/**
* 如果字段存的是enterpriseWechat,代表这个client是给到企业微信的app
*/
private String scope;
private String authorizedGrantTypes;
private String webServerRedirectUri;
private String authorities;
private String accessTokenValidity;
private String refreshTokenValidity;
private String additionalInformation;
private String autoapprove;
private String clientName;
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.springframework.data.annotation.Id;
import java.util.Date;
/**
* @author hubin
*/
@Data
@TableName("ISM_CUSTOMER_INFO")
public class SystemCustomerInfo {
@TableId
private Long customerId;
private Long originalCustomerId;
private Long batchId;
private Date insertTime;
private String name;
private String gender;
private Date birthday;
private int age;
private String mobile;
private String documentType;
private String documentNumber;
private String documentValidTo;
private String email;
private String nationality;
private String nation;
private String occupationCode;
private String occupationName;
private String annualIncome;
private String height;
private String weight;
private String education;
private String marriage;
private String politicalProfile;
private String religion;
private String avatar;
private String provinceCode;
private String provinceName;
private String cityCode;
private String cityName;
private String areaName;
private String areaCode;
private String address;
private String postcode;
private String inauguralBankCode;
private String inauguralBankName;
private String inauguralBankAccount;
private String renewalBankCode;
private String renewalBankName;
private String renewalBankAccount;
private String dataSeries;
private String dataSource;
private String dataSubSource;
private String manufacturerCode;
private String manufacturerName;
private String ifSmoking;
private String ifHaveCar;
private String carType;
private String ifHaveHouse;
private String ifHaveCreditCard;
private String ifHaveSocialSecurity;
private String ifHaveLoan;
private String ifHaveInsurancePolicy;
private String ifHaveProvidentFunds;
private String ifHaveChild;
private int childNum;
@TableField("child_1_age")
private int child1Age;
@TableField("child_2_age")
private int child2Age;
@TableField("child_3_age")
private int child3Age;
private String ifBuyedInsurance;
private String ifPlanInsurance;
private String insuranceBuyTime;
private String insuranceEnsureTime;
private String getCustomerTime;
private String getCustomerSource;
private Date createdTime;
private String marketerCode;
private String marketerName;
private String assignmentStatus;
private String assignmentCount;
private String recycleStatus;
private int recycleCount;
private String customerStatus;
private Double individualRating;
private String customerSource;
private Date updatedTime;
private String toAgencyCode;
private String toAgencyName;
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* 部门表
*
* @author jiaguokai
*/
@Data
@TableName("ISM_DEPARTMENT")
public class SystemDepartment {
private int id;
private String departmentCode;
private String departmentName;
private String agencyCode;
private String enable;
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* @author hubin
*/
@Data
@TableName("ISM_MARKETER")
public class SystemMarketer {
@TableId
private int id;
private String qywxId;
private String marketerCode;
private String marketerName;
private String gender;
private Date birthday;
private String mobile;
private String telephone;
private String email;
private String avatar;
private String education;
private String marriage;
private String politicalProfile;
private String religion;
private String nationality;
private String provinceCode;
private String provinceName;
private String cityCode;
private String cityName;
private String areaName;
private String address;
private String agencyCode;
private String agencyName;
private String departmentCode;
private String departmentName;
private String teamCode;
private String teamName;
private String position;
private String dialingTime;
private int currentAssignedAmount;
private int totalAssignedAmount;
private int turnover;
private double individualRating;
private String enable;
private String ifSeparation;
private Date createdTime;
private Date updatedTime;
//用于计算评分
@TableField(exist = false)
private Double rating;
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* 省份表
*
* @author jiaguokai
*/
@Data
@TableName("ISM_PROVINCE")
public class SystemProvince {
private int id;
private String provinceCode;
private String provinceName;
private String enable;
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
*
*
* 系统资源表,用于权限验证
* @author hubin
*/
@Data
@TableName("ISM_RESOURCE")
public class SystemResource {
private Long id;
private String resourceName;
private String resourceUrl;
private String method;
private String resourceType;
private Date createTime;
@TableField(exist = false)
private List<Long> roleIds;
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* 角色表,根据该表与 {@link SystemResource} 共同实现权限管理
* @author hubin
*/
@Data
@TableName("ISM_ROLE")
public class SystemRole {
private Long id;
private String name;
private String status;
private Date createTime;
private Date modifyTime;
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
*
* 资源权限关联表
* @author hubin
*/
@Data
@TableName("ISM_ROLE_RESOURCE")
public class SystemRoleResource {
private Long id;
private Long roleId;
private Long resourceId;
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* 销售小组表
*
* @author jiaguokai
*/
@Data
@TableName("ISM_DEPARTMENT")
public class SystemTeam {
private int id;
private String teamCode;
private String teamName;
private String departmentCode;
private String agencyCode;
private String enable;
}
package com.hungraim.ism.pojo.entity.system;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
import java.util.List;
/**
* @author hubin
*/
@Data
@NoArgsConstructor
@TableName("ISM_USER")
public class SystemUser {
@TableId(type = IdType.AUTO)
private Long id;
private String account;
private String password;
private String realName;
private String gender;
private String marketerCode;
private String userStatus;
private Date createdTime;
private Date updatedTime;
}
package com.hungraim.ism.pojo.entity.system;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* 用户-角色关联表
* @author hubin
*
*/
@Data
@TableName("ISM_USER_ROLE")
public class SystemUserRole {
private Long id;
private Long userId;
private Long roleId;
}
package com.hungraim.ism.pojo.vo.system;
import cn.hutool.core.collection.CollectionUtil;
import com.hungraim.ism.pojo.entity.system.SystemUser;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author hubin
*/
@Data
public class UserLoginInfoVO implements UserDetails {
private Collection<SimpleGrantedAuthority> authorities;
private final String username;
private final String password;
private final String name;
private final Long userId;
private String avatar;
private final Boolean enable;
public UserLoginInfoVO(SystemUser user) {
this.username = user.getAccount();
this.password = user.getPassword();
this.name = user.getRealName();
this.userId = user.getId();
this.enable = "1".equals(user.getUserStatus()) ;
}
public void setAuthorities(List<Long> roles){
if (CollectionUtil.isNotEmpty(roles)) {
authorities = new ArrayList<>();
roles.forEach(roleId -> authorities.add(new SimpleGrantedAuthority(String.valueOf(roleId))));
}
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.username;
}
@Override
public boolean isAccountNonExpired() {
return this.enable;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return this.enable;
}
}
package com.hungraim.ism.util;
/**
* @author hubin
*/
public interface IResultCode {
String getCode();
String getMsg();
}
package com.hungraim.ism.util;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.hungraim.ism.constant.AuthConstants;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sun.misc.BASE64Decoder;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;
/**
* @author hubin
*/
@Slf4j
public class RequestUtils {
public static HttpServletRequest getRequest() {
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
}
public static JSONObject getJwtPayload() {
String jwtPayload = getRequest().getHeader(AuthConstants.JWT_PAYLOAD_KEY);
return JSONUtil.parseObj(jwtPayload);
}
@SneakyThrows
public static String getAuthClientId() {
String clientId;
HttpServletRequest request = getRequest();
// 从请求路径中获取
clientId = request.getParameter(AuthConstants.CLIENT_ID_KEY);
if (StrUtil.isNotBlank(clientId)) {
return clientId;
}
// 从请求头获取
String basic = request.getHeader(AuthConstants.AUTHORIZATION_KEY);
if (StrUtil.isNotBlank(basic) && basic.startsWith(AuthConstants.BASIC_PREFIX)) {
basic = basic.replace(AuthConstants.BASIC_PREFIX, Strings.EMPTY);
String basicPlainText = new String(new BASE64Decoder().decodeBuffer(basic), StandardCharsets.UTF_8);
//client:secret
clientId = basicPlainText.split(":")[0];
}
return clientId;
}
/**
* 发起http post请求
*
* @param url 请求地址
* @param entity 请求参数
* @return 返回信息,出错返回空
*/
@SneakyThrows
public static String post(String url, JSONObject entity, Map<String, String> header) {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
try {
HttpPost httpPost = new HttpPost(url);
HttpHead httpHead = new HttpHead();
//设置head
if (header != null) {
header.forEach(httpHead::setHeader);
}
StringEntity se = new StringEntity(entity.toString(), "UTF-8");
se.setContentType("application/json");
httpPost.setEntity(se);
response = httpClient.execute(httpPost);
HttpEntity entity1 = response.getEntity();
String resStr = null;
if (entity1 != null) {
resStr = EntityUtils.toString(entity1, StandardCharsets.UTF_8);
}
httpClient.close();
response.close();
return resStr;
} catch (Exception e) {
log.error("POST请求:{},出现错误:{}", url, e.getMessage());
e.printStackTrace();
} finally {
if (httpClient != null) {
httpClient.close();
}
if (response != null) {
response.close();
}
}
return "";
}
/**
* 发起http get请求
*
* @param url 请求地址
* @return 返回信息,出错返回空
*/
@SneakyThrows
public static String get(String url) {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
try {
HttpGet httpGet = new HttpGet(url);
response = httpClient.execute(httpGet);
HttpEntity entity1 = response.getEntity();
String resStr = null;
if (entity1 != null) {
resStr = EntityUtils.toString(entity1, StandardCharsets.UTF_8);
}
httpClient.close();
response.close();
return resStr;
} catch (Exception e) {
log.error("get请求:{},出现错误:{}", url, e.getMessage());
e.printStackTrace();
} finally {
if (httpClient != null) {
httpClient.close();
}
if (response != null) {
response.close();
}
}
return "";
}
}
package com.hungraim.ism.util;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serializable;
/**
* 返回信息封装
* @author hubin
*/
@Data
public class Result<T> implements Serializable {
private String code;
private T data;
private String msg;
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer total;
public static <T> Result<T> success() {
return success(null);
}
public static <T> Result<T> success(T data) {
ResultCode rce = ResultCode.SUCCESS;
if (data instanceof Boolean && Boolean.FALSE.equals(data)) {
rce = ResultCode.SYSTEM_EXECUTION_ERROR;
}
return result(rce, data);
}
public static <T> Result<T> failed() {
return result(ResultCode.SYSTEM_EXECUTION_ERROR.getCode(), ResultCode.SYSTEM_EXECUTION_ERROR.getMsg(), null);
}
public static <T> Result<T> failed(String msg) {
return result(ResultCode.SYSTEM_EXECUTION_ERROR.getCode(), msg, null);
}
public static <T> Result<T> judge(boolean status) {
if (status) {
return success();
} else {
return failed();
}
}
public static <T> Result<T> failed(IResultCode resultCode) {
return result(resultCode.getCode(), resultCode.getMsg(), null);
}
private static <T> Result<T> result(IResultCode resultCode, T data) {
return result(resultCode.getCode(), resultCode.getMsg(), data);
}
private static <T> Result<T> result(String code, String msg, T data) {
Result<T> result = new Result<>();
result.setCode(code);
result.setData(data);
result.setMsg(msg);
return result;
}
public static <T> Result<T> success(T data, Long total) {
Result<T> result = new Result<>();
result.setCode(ResultCode.SUCCESS.getCode());
result.setMsg(ResultCode.SUCCESS.getMsg());
result.setData(data);
result.setTotal(total.intValue());
return result;
}
}
package com.hungraim.ism.util;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 常用的Result
* @author hubin
*/
@AllArgsConstructor
@NoArgsConstructor
public enum ResultCode implements IResultCode, Serializable {
//成功
SUCCESS("00000", "一切ok"),
//用户登陆异常
USER_LOGIN_ERROR("U0001", "用户登录异常"),
USER_NOT_EXIST("U0002", "用户不存在"),
MARKETER_NOT_EXIST("U0003", "营销员信息未找到"),
USERNAME_OR_PASSWORD_ERROR("U0003", "用户名密码错误"),
//系统执行出错
SYSTEM_EXECUTION_ERROR("S0001", "系统异常"),
//客户端认证失败
CLIENT_AUTHENTICATION_FAILED("A0001", "客户端认证失败"),
//没有访问权限
NO_AUTHORITY("A0002", "没有访问权限"),
AUTHORIZED_ERROR("A0300", "访问权限异常"),
ACCESS_UNAUTHORIZED("A0301", "访问未授权"),
TOKEN_INVALID_OR_EXPIRED("A0230", "token无效或已过期"),
;
private String code;
private String msg;
@Override
public String getCode() {
return code;
}
@Override
public String getMsg() {
return msg;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>com.hungraim.ism</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-mybatis</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- 引用Mybatis 和 Mysql驱动开始 -->
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 引用Mybatis 和 Mysql驱动结束 -->
</dependencies>
</project>
package com.hungraim.ism.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
/**
* @author hubin
*/
@Configuration
//开启事务
@EnableTransactionManagement
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix="spring.datasource")
public DataSource dataSource(){
return new DriverManagerDataSource();
}
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>com.hungraim.ism</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-redis</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--redis 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!--redis依赖 end-->
</dependencies>
</project>
package com.hungraim.ism.redis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @author hubin
*/
@Configuration
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class RedisConfig {
@Bean
@SuppressWarnings("unchecked")
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
// 用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
// 指定要序列化的域(field,get,set),访问修饰符(public,private,protected)
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// value序列化方式采用jackson
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// hash的key也采用String的序列化方
redisTemplate.setHashKeySerializer(stringRedisSerializer);
// hash的value序列化方式采用jackson
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ism</artifactId>
<groupId>com.hungraim.ism</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>common-core</module>
<module>common-mybatis</module>
<module>common-redis</module>
</modules>
<artifactId>common</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.10.5</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
<version>3.3.1</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
<version>5.3.3.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
<distributionManagement>
<repository>
<id>releases</id>
<name>Nexus Release Repository</name>
<url>http://121.5.28.27:9091/nexus/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>http://121.5.28.27:9091/nexus/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
#指定依赖的镜像
FROM localhost:9999/library/java:8
#springboot
VOLUME /tmp
#容器使用端口
EXPOSE 8001
#添加jar包入容器
ADD gateway-service/target/gateway-0.0.1.jar app.jar
#改名
RUN sh -c 'touch /app.jar'
#容器启动java
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
apiVersion: apps/v1
kind: Deployment
metadata:
name: ism-gateway-service
namespace: ism-service
labels:
app: ism-gateway-service
spec:
replicas: 1
selector:
matchLabels:
app: ism-gateway-service
template:
metadata:
labels:
app: ism-gateway-service
spec:
imagePullSecrets:
- name: ism-harbor
containers:
- name: ism-gateway-service #TODO:pod的名称,必须字段,名称唯一且对象创建后不可以被修改
image: localhost:9999/ism/ism-gateway-service:latest #TODO:镜像仓库的路径/镜像的名称:镜像的标签,
imagePullPolicy: Always #Always(总是去仓库下载),Never(从不去仓库下载),IfNotPresent(如果本地没有就去仓库下载),默认是"IfNotPresent"
ports:
- containerPort: 8001 #TODO:containerPort是pod内部容器的端口,targetPort映射到containerPort;例如,mysql服务需要暴露3306端口,redis暴露6379端口
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ism</artifactId>
<groupId>com.hungraim.ism</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway</artifactId>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-nacos-config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.hungraim.ism</groupId>
<artifactId>common-core</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>com.hungraim.ism</groupId>
<artifactId>common-redis</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!--重要-->
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.hungraim.ism;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author hubin
*/
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
package com.hungraim.ism.gateway.config;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator;
import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Configuration
public class CorsConfig {
private static final String MAX_AGE = "18000L";
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
HttpHeaders requestHeaders = request.getHeaders();
ServerHttpResponse response = ctx.getResponse();
HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
HttpHeaders headers = response.getHeaders();
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders
.getAccessControlRequestHeaders());
if(requestMethod != null){
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
}
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}
}
package com.hungraim.ism.gateway.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* 路由类配置
*/
@Configuration
public class GatewayConfig {
public static final long DEFAULT_TIMEOUT = 30000;
public static String NACOS_SERVER_ADDR;
public static String NACOS_NAMESPACE;
public static String NACOS_ROUTE_DATA_ID;
public static String NACOS_ROUTE_GROUP;
@Value("${spring.cloud.nacos.discovery.server-addr}")
public void setNacosServerAddr(String nacosServerAddr){
NACOS_SERVER_ADDR = nacosServerAddr;
}
@Value("${spring.cloud.nacos.discovery.namespace}")
public void setNacosNamespace(String nacosNamespace){
NACOS_NAMESPACE = nacosNamespace;
}
@Value("${nacos.gateway.route.config.data-id}")
public void setNacosRouteDataId(String nacosRouteDataId){
NACOS_ROUTE_DATA_ID = nacosRouteDataId;
}
@Value("${nacos.gateway.route.config.group}")
public void setNacosRouteGroup(String nacosRouteGroup){
NACOS_ROUTE_GROUP = nacosRouteGroup;
}
}
package com.hungraim.ism.gateway.config;
import cn.hutool.json.JSONUtil;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.hungraim.ism.gateway.service.impl.NacosDynamicRouteServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
* 通过nacos下发动态路由配置,监听Nacos中gateway-route配置
* @author hubin
*/
@Slf4j
@Component
@DependsOn({"gatewayConfig"}) // 依赖于gatewayConfig bean
public class NacosGatewayDefineConfig implements CommandLineRunner {
private final NacosDynamicRouteServiceImpl dynamicRouteService;
private ConfigService configService;
@Autowired
public NacosGatewayDefineConfig(NacosDynamicRouteServiceImpl dynamicRouteService) {
this.dynamicRouteService = dynamicRouteService;
}
@Override
public void run(String... args) {
log.info("gateway route init...");
try {
configService = initConfigService();
if (configService == null) {
log.warn("initConfigService fail");
return;
}
String configInfo = configService.getConfig(GatewayConfig.NACOS_ROUTE_DATA_ID, GatewayConfig.NACOS_ROUTE_GROUP, GatewayConfig.DEFAULT_TIMEOUT);
log.info("获取网关当前配置:\r\n{}", configInfo);
List<RouteDefinition> definitionList = JSONUtil.toList(configInfo, RouteDefinition.class);
for (RouteDefinition definition : definitionList) {
log.info("update route : {}", definition.toString());
dynamicRouteService.add(definition);
}
} catch (Exception e) {
log.error("初始化网关路由时发生错误", e);
}
dynamicRouteByNacosListener(GatewayConfig.NACOS_ROUTE_DATA_ID, GatewayConfig.NACOS_ROUTE_GROUP);
}
/**
* 监听Nacos下发的动态路由配置
*
* @param dataId dataId
* @param group group
*/
public void dynamicRouteByNacosListener(String dataId, String group) {
try {
configService.addListener(dataId, group, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
log.info("进行网关更新:\n\r{}", configInfo);
List<RouteDefinition> definitionList = JSONUtil.toList(configInfo, RouteDefinition.class);
log.info("update route : {}", definitionList.toString());
dynamicRouteService.updateList(definitionList);
}
@Override
public Executor getExecutor() {
log.info("getExecutor\n\r");
return null;
}
});
} catch (NacosException e) {
log.error("从nacos接收动态路由配置出错!!!", e);
}
}
/**
* 初始化网关路由 nacos config
*
* @return ConfigService
*/
private ConfigService initConfigService() {
try {
Properties properties = new Properties();
properties.setProperty("serverAddr", GatewayConfig.NACOS_SERVER_ADDR);
properties.setProperty("namespace", GatewayConfig.NACOS_NAMESPACE);
return configService = NacosFactory.createConfigService(properties);
} catch (Exception e) {
log.error("初始化网关路由时发生错误", e);
return null;
}
}
}
package com.hungraim.ism.gateway.config;
import cn.hutool.json.JSONUtil;
import com.hungraim.ism.constant.AuthConstants;
import com.hungraim.ism.gateway.security.AuthorizationManager;
import com.hungraim.ism.util.Result;
import com.hungraim.ism.util.ResultCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
/**
* 资源服务器配置
*
* @author hubin
*/
@Configuration
@EnableWebFluxSecurity
public class ResourceServerConfig {
private final AuthorizationManager authorizationManager;
@Autowired
public ResourceServerConfig(AuthorizationManager authorizationManager) {
this.authorizationManager = authorizationManager;
}
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http.oauth2ResourceServer().jwt()
.jwtAuthenticationConverter(jwtAuthenticationConverter());
http.authorizeExchange()
.pathMatchers("/oauth/token").permitAll()
.anyExchange().access(authorizationManager)
.and()
.exceptionHandling()
// 处理未授权
.accessDeniedHandler(accessDeniedHandler())
//处理未认证
.authenticationEntryPoint(authenticationEntryPoint())
.and().csrf().disable();
return http.build();
}
/**
* 未授权
*/
@SuppressWarnings("unchecked")
@Bean
ServerAccessDeniedHandler accessDeniedHandler() {
return (exchange, denied) -> Mono.defer(() -> Mono.just(exchange.getResponse()))
.flatMap(response -> ResourceServerConfig.writeFailedToResponse(response, ResultCode.ACCESS_UNAUTHORIZED));
}
/**
* token无效或者已过期自定义响应
*/
@SuppressWarnings("unchecked")
@Bean
ServerAuthenticationEntryPoint authenticationEntryPoint() {
return (exchange, e) -> Mono.defer(() -> Mono.just(exchange.getResponse()))
.flatMap(response -> ResourceServerConfig.writeFailedToResponse(response, ResultCode.TOKEN_INVALID_OR_EXPIRED));
}
/**
* @link https://blog.csdn.net/qq_24230139/article/details/105091273
* ServerHttpSecurity没有将jwt中authorities的负载部分当做Authentication
* 需要把jwt的Claim中的authorities加入
* 方案:重新定义权限管理器,默认转换器JwtGrantedAuthoritiesConverter
*/
@Bean
public Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthorityPrefix(AuthConstants.AUTHORITY_PREFIX);
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName(AuthConstants.JWT_AUTHORITIES_KEY);
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
}
public static Mono writeFailedToResponse(ServerHttpResponse response, ResultCode resultCode){
response.setStatusCode(HttpStatus.OK);
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getHeaders().set("Access-Control-Allow-Origin", "*");
response.getHeaders().set("Cache-Control", "no-cache");
String body = JSONUtil.toJsonStr(Result.failed(resultCode));
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
return response.writeWith(Mono.just(buffer))
.doOnError(error -> DataBufferUtils.release(buffer));
}
}
package com.hungraim.ism.gateway.security;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.hungraim.ism.constant.AuthConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import reactor.core.publisher.Mono;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* 鉴权管理器
* @author hubin
*/
@Component
@Slf4j
public class AuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {
private final RedisTemplate redisTemplate;
@Autowired
public AuthorizationManager(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
@SuppressWarnings("unchecked")
public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
ServerHttpRequest request = authorizationContext.getExchange().getRequest();
String path = request.getMethodValue() + "_" + request.getURI().getPath();
log.info("请求,path={}", path);
PathMatcher pathMatcher = new AntPathMatcher();
// 对应跨域的预检请求直接放行
if (request.getMethod() == HttpMethod.OPTIONS) {
return Mono.just(new AuthorizationDecision(true));
}
// 非管理端路径无需鉴权直接放行
if (!pathMatcher.match(AuthConstants.ADMIN_URL_PATTERN, path)) {
log.info("请求无需鉴权,path={}", path);
return Mono.just(new AuthorizationDecision(true));
}
// token为空拒绝访问
String token = request.getHeaders().getFirst(AuthConstants.AUTHORIZATION_KEY);
log.info("请求token,token={}", token);
if (StrUtil.isBlank(token)) {
log.info("请求token为空拒绝访问,path={}", path);
return Mono.just(new AuthorizationDecision(false));
}
// 从缓存取资源权限角色关系列表
Map<Object, Object> permissionRoles = redisTemplate.opsForHash().entries(AuthConstants.PERMISSION_ROLES_KEY);
Iterator<Object> iterator = permissionRoles.keySet().iterator();
// 请求路径匹配到的资源需要的角色权限集合authorities统计
Set<String> authorities = new HashSet<>();
while (iterator.hasNext()) {
String pattern = (String) iterator.next();
if (pathMatcher.match(pattern, path)) {
authorities.addAll(Convert.toList(String.class, permissionRoles.get(pattern)));
}
}
log.info("require authorities:{}", authorities);
return mono
.filter(Authentication::isAuthenticated)
.flatMapIterable(Authentication::getAuthorities)
.map(GrantedAuthority::getAuthority)
.any(roleId -> {
// roleId是请求用户的角色(格式:ROLE_{roleId}),authorities是请求资源所需要角色的集合
log.info("访问路径:{}", path);
log.info("用户角色信息:{}", roleId);
log.info("资源需要权限authorities:{}", authorities);
return authorities.contains(roleId);
})
.map(AuthorizationDecision::new)
.defaultIfEmpty(new AuthorizationDecision(false));
}
}
package com.hungraim.ism.gateway.service;
import org.springframework.cloud.gateway.route.RouteDefinition;
import java.util.List;
/**
* @author hubin
*/
public interface INacosDynamicRouteService {
/**
* 添加路由
* @param definition definition
*/
void add(RouteDefinition definition);
/**
* 更新路由
* @param definition definition
*/
void updateById(RouteDefinition definition);
/**
* 更新路由列表
* @param definitions definitions列表
*/
void updateList(List<RouteDefinition> definitions);
/**
* 删除路由
* @param definitionId definitions列表
*/
void delete(String definitionId);
}
package com.hungraim.ism.gateway.service.impl;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.hungraim.ism.gateway.service.INacosDynamicRouteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.util.List;
/**
* @author hubin
*/
@Service
@Slf4j
public class NacosDynamicRouteServiceImpl implements INacosDynamicRouteService {
private final RouteDefinitionWriter routeDefinitionWriter;
private final ApplicationEventPublisher publisher;
private final RouteDefinitionLocator routeDefinitionLocator;
@Autowired
public NacosDynamicRouteServiceImpl(RouteDefinitionWriter routeDefinitionWriter, ApplicationEventPublisher publisher, RouteDefinitionLocator routeDefinitionLocator) {
this.routeDefinitionWriter = routeDefinitionWriter;
this.publisher = publisher;
this.routeDefinitionLocator = routeDefinitionLocator;
}
@Override
public void delete(String id) {
log.info("gateway delete route id {}", id);
this.routeDefinitionWriter.delete(Mono.just(id)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
}
@Override
public void updateList(List<RouteDefinition> definitions) {
log.info("gateway update route {}", definitions);
// 删除缓存routerDefinition
List<RouteDefinition> routeDefinitionsExits = routeDefinitionLocator.getRouteDefinitions().buffer().blockFirst();
if (!CollectionUtils.isEmpty(routeDefinitionsExits)) {
routeDefinitionsExits.forEach(routeDefinition -> {
log.info("delete routeDefinition:{}", routeDefinition);
delete(routeDefinition.getId());
});
}
definitions.forEach(this::updateById);
}
@Override
public void updateById(RouteDefinition definition) {
log.info("gateway update route {}", definition);
this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
}
@Override
public void add(RouteDefinition definition) {
log.info("gateway add route {}", definition);
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
}
}
package com.hungraim.ism.gateway.utils;
import cn.hutool.json.JSONUtil;
import com.hungraim.ism.util.Result;
import com.hungraim.ism.util.ResultCode;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
/**
* @author hubin
*/
public class WebUtils {
}
spring:
devtools:
restart:
enabled: true
additional-paths: src/main/java
application:
name: ISM-GATEWAY-SERVICE
cloud:
nacos:
discovery:
server-addr: qw.hungraim.com:31158
namespace: 74494ee6-1c9c-4165-97d2-d876f4b4befc
config:
namespace: 74494ee6-1c9c-4165-97d2-d876f4b4befc
server-addr: qw.hungraim.com:31158
file-extension: yaml # 必须修改成yaml
extension-configs:
- data-id: ism-basic.yaml
group: common
refresh: true
- data-id: ism-database.yaml
group: common
refresh: true
- data-id: ism-gateway.yaml
group: gateway
refresh: true
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: '*'
allowedMethods: '*'
nacos:
gateway:
route:
config:
data-id: ism-gateway-router
group: common
server:
port: 8001
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modules>
<module>gateway-service</module>
<module>auth-service</module>
<module>common</module>
<module>system</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<packaging>pom</packaging>
<groupId>com.hungraim.ism</groupId>
<artifactId>ism</artifactId>
<version>0.0.1</version>
<name>spring-cloud-init</name>
<description>parent</description>
<properties>
<java.version>1.8</java.version>
<spring.cloud.version>Hoxton.SR8</spring.cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--工具类 官网:https://www.hutool.cn/-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.9</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ism</artifactId>
<groupId>com.hungraim.ism</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>system</artifactId>
<packaging>pom</packaging>
<modules>
<module>system-api</module>
<module>system-user-service</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
</dependencies>
<distributionManagement>
<repository>
<id>releases</id>
<name>Nexus Release Repository</name>
<url>http://121.5.28.27:9091/nexus/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>http://121.5.28.27:9091/nexus/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>system</artifactId>
<groupId>com.hungraim.ism</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>system-api</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</dependency>
<dependency>
<groupId>com.hungraim.ism</groupId>
<artifactId>common-core</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
<distributionManagement>
<repository>
<id>releases</id>
<name>Nexus Release Repository</name>
<url>http://121.5.28.27:9091/nexus/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>http://121.5.28.27:9091/nexus/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
package com.hungraim.ism.api;
import com.hungraim.ism.pojo.entity.system.SystemMarketer;
import com.hungraim.ism.pojo.entity.system.SystemUser;
import com.hungraim.ism.util.Result;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
/**
* @author hubin
*/
@FeignClient("ISM-SYSTEM-user-service-SERVICE")
public interface SystemUserFeignService {
/**
* feign api 根据用户账号获取用户基本信息
* @param account 用户账号
* @return 用户信息
*/
@GetMapping("/api.system/user/loadUserInfoByAccount/{account}")
Result<SystemUser> loadUserInfoByAccount(@PathVariable String account);
/**
* feign api 根据用户id获取用户权限列表
* @param id 用户id
* @return 权限列表
*/
@GetMapping("/api.system/user/loadUserRolesByUserId/{id}")
Result<List<Long>> loadUserRolesByUserId(@PathVariable Long id);
/**
* feign api 根据用户表关联的marketerCode获取用户绑定的营销员信息
* @param code marketerCode
* @return 营销员信息
*/
@GetMapping("/api.system/user/loadUserDetailByCode/{code}")
Result<SystemMarketer> loadUserDetailByCode(@PathVariable String code);
}
#指定依赖的镜像
FROM localhost:9999/library/java:8
#springboot
VOLUME /tmp
#容器使用端口
EXPOSE 8002
#添加jar包入容器
ADD system/system-user-service/target/system-user-0.0.1.jar app.jar
#改名
RUN sh -c 'touch /app.jar'
#容器启动java
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
apiVersion: apps/v1
kind: Deployment
metadata:
name: ism-system-user-service
namespace: ism-service
labels:
app: ism-system-user-service
spec:
replicas: 1
selector:
matchLabels:
app: ism-system-user-service
template:
metadata:
labels:
app: ism-system-user-service
spec:
imagePullSecrets:
- name: ism-harbor
containers:
- name: ism-system-user-service #TODO:pod的名称,必须字段,名称唯一且对象创建后不可以被修改
image: localhost:9999/ism/ism-system-user-service:latest #TODO:镜像仓库的路径/镜像的名称:镜像的标签,
imagePullPolicy: Always #Always(总是去仓库下载),Never(从不去仓库下载),IfNotPresent(如果本地没有就去仓库下载),默认是"IfNotPresent"
ports:
- containerPort: 8001 #TODO:containerPort是pod内部容器的端口,targetPort映射到containerPort;例如,mysql服务需要暴露3306端口,redis暴露6379端口
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>system</artifactId>
<groupId>com.hungraim.ism</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>system-user</artifactId>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-nacos-config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!--基础包-->
<dependency>
<groupId>com.hungraim.ism</groupId>
<artifactId>common-core</artifactId>
<version>0.0.1</version>
<exclusions>
<exclusion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.hungraim.ism</groupId>
<artifactId>common-mybatis</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>com.hungraim.ism</groupId>
<artifactId>common-redis</artifactId>
<version>0.0.1</version>
</dependency>
<!--基础包 end-->
<!-- spring boot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!--重要-->
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.hungraim.ism;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 系统服务,后台运行的一些业务写在这个服务下,比如定时服务等
* @author hubin
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableScheduling
public class SystemApplication {
public static void main(String[] args) {
SpringApplication.run(SystemApplication.class, args);
}
}
package com.hungraim.ism.component;
import com.hungraim.ism.system.service.impl.SystemResourceServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
/**
*
* 服务运行时将资源和角色对应关系缓存到redis
* @author hubin
*/
@Component
@Slf4j
public class InitResourceRoleCacheRunner implements CommandLineRunner {
private final SystemResourceServiceImpl resourceService;
@Autowired
public InitResourceRoleCacheRunner(SystemResourceServiceImpl resourceService) {
this.resourceService = resourceService;
}
@Override
public void run(String... args) {
resourceService.refreshPermissionRolesCache();
}
}
package com.hungraim.ism.system.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hungraim.ism.pojo.entity.system.SystemAgency;
import com.hungraim.ism.pojo.entity.system.SystemCity;
import com.hungraim.ism.pojo.entity.system.SystemProvince;
import com.hungraim.ism.system.service.ISystemAgencyService;
import com.hungraim.ism.system.service.ISystemCityService;
import com.hungraim.ism.system.service.ISystemProvinceService;
import com.hungraim.ism.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 下拉框选项
*
* @author jiaguokai
*/
@RestController
@RequestMapping("/api.system/dropDown")
@Slf4j
public class DropDownController {
@Autowired
private ISystemProvinceService provinceService;
@Autowired
private ISystemCityService cityService;
@Autowired
private ISystemAgencyService agencyService;
/**
* 所有可用机构
*
* @return
*/
@RequestMapping(value = "/loadAgency", method = RequestMethod.GET)
public Result loadAgency() {
List<SystemAgency> agencyList = agencyService.list(new LambdaQueryWrapper<SystemAgency>().eq(SystemAgency::getEnable, "1"));
if (agencyList == null) {
log.warn("DropDownController --- loadAgency --- 当前无可用机构");
return Result.failed("当前无可用机构");
}
return Result.success(agencyList);
}
/**
* 所有可用省份
*
* @return
*/
@RequestMapping(value = "/loadProvince", method = RequestMethod.GET)
public Result loadProvince() {
List<SystemProvince> provinceList = provinceService.list(new LambdaQueryWrapper<SystemProvince>().eq(SystemProvince::getEnable, "1"));
if (provinceList == null) {
log.warn("DropDownController --- loadProvince --- 当前无可用省份");
return Result.failed("当前无可用省份");
}
return Result.success(provinceList);
}
/**
* 当前省份的可用城市
*
* @param province
* @return
*/
@GetMapping(value = "/loadCity/{province}")
public Result loadCity(@PathVariable String province) {
List<SystemCity> cityList = cityService.list(new LambdaQueryWrapper<SystemCity>().eq(SystemCity::getEnable, "1").eq(SystemCity::getProvinceCode, province));
if (cityList == null) {
log.warn("DropDownController --- loadCity --- 当前省份无可用城市");
return Result.failed("当前省份无可用城市");
}
return Result.success(cityList);
}
}
package com.hungraim.ism.system.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hungraim.ism.pojo.entity.system.SystemMarketer;
import com.hungraim.ism.pojo.entity.system.SystemUser;
import com.hungraim.ism.pojo.entity.system.SystemUserRole;
import com.hungraim.ism.system.service.ISystemMarketerService;
import com.hungraim.ism.system.service.ISystemUserRoleService;
import com.hungraim.ism.system.service.ISystemUserService;
import com.hungraim.ism.system.service.impl.SystemUserRoleServiceImpl;
import com.hungraim.ism.system.service.impl.SystemUserServiceImpl;
import com.hungraim.ism.util.Result;
import com.hungraim.ism.util.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author hubin
*/
@RestController
@RequestMapping("/api.system/user")
@Slf4j
public class UserController {
private final ISystemUserService userInfoService;
private final ISystemUserRoleService userRoleService;
private final ISystemMarketerService marketerService;
@Autowired
public UserController(SystemUserServiceImpl userInfoService, SystemUserRoleServiceImpl userRoleService, ISystemMarketerService marketerService) {
this.userInfoService = userInfoService;
this.userRoleService = userRoleService;
this.marketerService = marketerService;
}
/**
* 根据用户账号获取用户基本信息
*
* @param account 用户账号
* @return 营销员信息
*/
@GetMapping("/loadUserInfoByAccount/{account}")
public Result<SystemUser> loadUserInfoByAccount(@PathVariable String account) {
log.info("user:{} 请求登陆。。。", account);
SystemUser systemUser = userInfoService.getOne(new LambdaQueryWrapper<SystemUser>().eq(SystemUser::getAccount, account));
if (systemUser == null) {
log.warn("user:{} 账号未找到!", account);
return Result.failed(ResultCode.USER_NOT_EXIST);
}
return Result.success(systemUser);
}
/**
* 根据用户id获取用户权限
*
* @param id 用户id
* @return 权限列表
*/
@GetMapping("/loadUserRolesByUserId/{id}")
public Result loadUserRolesByUserId(@PathVariable Long id) {
List<Long> roleIds = userRoleService.list(new LambdaQueryWrapper<SystemUserRole>()
.eq(SystemUserRole::getUserId, id)
).stream().map(SystemUserRole::getRoleId).collect(Collectors.toList());
log.info("user:{},拥有的权限:{}", id, roleIds);
return Result.success(roleIds);
}
/**
* 根据用户表关联的marketerCode获取用户绑定的营销员信息
*
* @param code 营销员id
* @return 权限列表
*/
@GetMapping("/loadUserDetailByCode/{code}")
public Result loadUserDetailByCode(@PathVariable String code) {
SystemMarketer marketer = marketerService.getOne(new LambdaQueryWrapper<SystemMarketer>()
.eq(SystemMarketer::getMarketerCode, code));
if (marketer == null) {
log.warn("code:{} 营销员信息未找到!", code);
return Result.failed(ResultCode.MARKETER_NOT_EXIST);
}
return Result.success(marketer);
}
}
package com.hungraim.ism.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hungraim.ism.pojo.entity.system.SystemAgency;
import org.apache.ibatis.annotations.Mapper;
/**
* @author hubin
*/
@Mapper
public interface SystemAgencyMapper extends BaseMapper<SystemAgency> {
}
package com.hungraim.ism.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hungraim.ism.pojo.entity.system.SystemCity;
import org.apache.ibatis.annotations.Mapper;
/**
* @author jiaguokai
*/
@Mapper
public interface SystemCityMapper extends BaseMapper<SystemCity> {
}
package com.hungraim.ism.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hungraim.ism.pojo.entity.system.SystemCustomerInfo;
import org.apache.ibatis.annotations.Mapper;
/**
* 客户信息
* @author hubin
*/
@Mapper
public interface SystemCustomerInfoMapper extends BaseMapper<SystemCustomerInfo> {
}
package com.hungraim.ism.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hungraim.ism.pojo.entity.system.SystemMarketer;
import org.apache.ibatis.annotations.Mapper;
/**
* @author hubin
*/
@Mapper
public interface SystemMarketerMapper extends BaseMapper<SystemMarketer> {
}
package com.hungraim.ism.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hungraim.ism.pojo.entity.system.SystemProvince;
import org.apache.ibatis.annotations.Mapper;
/**
* @author jiaguokai
*/
@Mapper
public interface SystemProvinceMapper extends BaseMapper<SystemProvince> {
}
package com.hungraim.ism.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hungraim.ism.pojo.entity.system.SystemResource;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* @author hubin
*/
@Mapper
public interface SystemResourceMapper extends BaseMapper<SystemResource> {
/**
* 查询所有资源对应的角色
* @return list
*/
@Select("SELECT ID,RESOURCE_NAME,RESOURCE_URL,METHOD FROM ISM_RESOURCE")
@Results({
@Result(property = "roleIds", column = "id",many = @Many(select = "com.hungraim.ism.system.dao.SystemRoleResourceMapper.listRoleIds"))
})
List<SystemResource> listResourceRoles();
}
package com.hungraim.ism.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hungraim.ism.pojo.entity.system.SystemRole;
import org.apache.ibatis.annotations.Mapper;
/**
* 角色
* @author hubin
*/
@Mapper
public interface SystemRoleMapper extends BaseMapper<SystemRole> {
}
package com.hungraim.ism.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hungraim.ism.pojo.entity.system.SystemRoleResource;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 资源权限关联表mapper
* @author hubin
*/
@Mapper
public interface SystemRoleResourceMapper extends BaseMapper<SystemRoleResource> {
/**
* 根据资源id查找角色id
* @param resourceId 资源id
* @return 角色id
*/
@Select("SELECT ROLE_ID FROM ISM_ROLE_RESOURCE WHERE RESOURCE_ID = #{resourceId} ")
List<Long> listRoleIds(long resourceId);
}
package com.hungraim.ism.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hungraim.ism.pojo.entity.system.SystemUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
/**
* 用户
* @author hubin
*/
@Mapper
public interface SystemUserMapper extends BaseMapper<SystemUser> {
}
package com.hungraim.ism.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hungraim.ism.pojo.entity.system.SystemUserRole;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SystemUserRoleMapper extends BaseMapper<SystemUserRole> {
}
package com.hungraim.ism.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hungraim.ism.pojo.entity.system.SystemAgency;
/**
* @author hubin
*/
public interface ISystemAgencyService extends IService<SystemAgency> {
}
package com.hungraim.ism.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hungraim.ism.pojo.entity.system.SystemCity;
/**
* @author jiaguokai
*/
public interface ISystemCityService extends IService<SystemCity> {
}
package com.hungraim.ism.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hungraim.ism.pojo.entity.system.SystemCustomerInfo;
/**
* @author hubin
*/
public interface ISystemCustomerInfoService extends IService<SystemCustomerInfo> {
}
package com.hungraim.ism.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hungraim.ism.pojo.entity.system.SystemMarketer;
/**
* @author hubin
*/
public interface ISystemMarketerService extends IService<SystemMarketer> {
}
package com.hungraim.ism.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hungraim.ism.pojo.entity.system.SystemProvince;
/**
* @author jiaguokai
*/
public interface ISystemProvinceService extends IService<SystemProvince> {
}
package com.hungraim.ism.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hungraim.ism.pojo.entity.system.SystemResource;
import java.util.List;
/**
* 资源
* @author hubin
*/
public interface ISystemResourceService extends IService<SystemResource> {
/**
* 将mysql中的资源角色关系缓存到redis中
*/
void refreshPermissionRolesCache();
/**
* 查询所有资源对应的角色
* @return list
*/
List<SystemResource> listResourceRoles();
}
package com.hungraim.ism.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hungraim.ism.pojo.entity.system.SystemRoleResource;
/**
* @author hubin
*/
public interface ISystemRoleResourceService extends IService<SystemRoleResource> {
}
package com.hungraim.ism.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hungraim.ism.pojo.entity.system.SystemRole;
/**
* 角色
* @author hubin
*/
public interface ISystemRoleService extends IService<SystemRole> {
}
package com.hungraim.ism.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hungraim.ism.pojo.entity.system.SystemUserRole;
/**
* @author hubin
*/
public interface ISystemUserRoleService extends IService<SystemUserRole> {
}
package com.hungraim.ism.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hungraim.ism.pojo.entity.system.SystemUser;
/**
* @author hubin
*/
public interface ISystemUserService extends IService<SystemUser> {
}
package com.hungraim.ism.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hungraim.ism.pojo.entity.system.SystemAgency;
import com.hungraim.ism.system.dao.SystemAgencyMapper;
import com.hungraim.ism.system.service.ISystemAgencyService;
import org.springframework.stereotype.Service;
/**
* @author hubin
*/
@Service
public class SystemAgencyServiceImpl extends ServiceImpl<SystemAgencyMapper, SystemAgency> implements ISystemAgencyService {
}
package com.hungraim.ism.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hungraim.ism.pojo.entity.system.SystemCity;
import com.hungraim.ism.system.dao.SystemCityMapper;
import com.hungraim.ism.system.service.ISystemCityService;
import org.springframework.stereotype.Service;
/**
* @author jiaguokai
*/
@Service
public class SystemCityServiceImpl extends ServiceImpl<SystemCityMapper, SystemCity> implements ISystemCityService {
}
package com.hungraim.ism.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hungraim.ism.system.dao.SystemCustomerInfoMapper;
import com.hungraim.ism.system.service.ISystemCustomerInfoService;
import com.hungraim.ism.pojo.entity.system.SystemCustomerInfo;
import org.springframework.stereotype.Service;
/**
* @author hubin
*/
@Service
public class SystemCustomerInfoServiceImpl extends ServiceImpl<SystemCustomerInfoMapper, SystemCustomerInfo> implements ISystemCustomerInfoService {
}
package com.hungraim.ism.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hungraim.ism.pojo.entity.system.SystemMarketer;
import com.hungraim.ism.system.dao.SystemMarketerMapper;
import com.hungraim.ism.system.service.ISystemMarketerService;
import org.springframework.stereotype.Service;
/**
* @author hubin
*/
@Service
public class SystemMarketerServiceImpl extends ServiceImpl<SystemMarketerMapper, SystemMarketer> implements ISystemMarketerService {
}
package com.hungraim.ism.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hungraim.ism.pojo.entity.system.SystemProvince;
import com.hungraim.ism.system.dao.SystemProvinceMapper;
import com.hungraim.ism.system.service.ISystemProvinceService;
import org.springframework.stereotype.Service;
/**
* @author jiaguokai
*/
@Service
public class SystemProvinceServiceImpl extends ServiceImpl<SystemProvinceMapper, SystemProvince> implements ISystemProvinceService {
}
package com.hungraim.ism.system.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hungraim.ism.constant.AuthConstants;
import com.hungraim.ism.pojo.entity.system.SystemResource;
import com.hungraim.ism.system.dao.SystemResourceMapper;
import com.hungraim.ism.system.service.ISystemResourceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author hubin
*/
@Service
@Slf4j
public class SystemResourceServiceImpl extends ServiceImpl<SystemResourceMapper, SystemResource> implements ISystemResourceService {
private final RedisTemplate redisTemplate;
@Autowired
public SystemResourceServiceImpl(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 将mysql中的资源角色关系缓存到redis中
*/
@Override
@SuppressWarnings("unchecked")
public void refreshPermissionRolesCache(){
log.info("refreshPermissionRolesCache run...");
redisTemplate.delete(AuthConstants.RESOURCE_ROLE_KEY);
List<SystemResource> permissions = this.listResourceRoles();
Map<String, List<String>> permissionRoles = new TreeMap<>();
Optional.ofNullable(permissions).orElse(new ArrayList<>()).forEach(permission -> {
// 转换 roleId -> ROLE_{roleId}
List<String> roles = Optional.ofNullable(permission.getRoleIds())
.orElse(new ArrayList<>())
.stream()
.map(roleId -> AuthConstants.AUTHORITY_PREFIX + roleId)
.collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(roles)) {
permissionRoles.put(permission.getMethod() +"_"+ permission.getResourceUrl(), roles);
}
redisTemplate.opsForHash().putAll(AuthConstants.PERMISSION_ROLES_KEY, permissionRoles);
});
}
@Override
public List<SystemResource> listResourceRoles() {
return this.baseMapper.listResourceRoles();
}
}
package com.hungraim.ism.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hungraim.ism.pojo.entity.system.SystemUserRole;
import com.hungraim.ism.system.dao.SystemUserRoleMapper;
import com.hungraim.ism.system.service.ISystemUserRoleService;
import org.springframework.stereotype.Service;
@Service
public class SystemUserRoleServiceImpl extends ServiceImpl<SystemUserRoleMapper, SystemUserRole> implements ISystemUserRoleService {
}
package com.hungraim.ism.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hungraim.ism.pojo.entity.system.SystemUser;
import com.hungraim.ism.system.dao.SystemUserMapper;
import com.hungraim.ism.system.dao.SystemUserRoleMapper;
import com.hungraim.ism.system.service.ISystemUserService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author hubin
*/
@Service
public class SystemUserServiceImpl extends ServiceImpl<SystemUserMapper, SystemUser> implements ISystemUserService {
@Resource
private SystemUserMapper userMapper;
@Resource
private SystemUserRoleMapper userRoleMapper;
}
spring:
devtools:
restart:
enabled: true
additional-paths: src/main/java
application:
name: ISM-SYSTEM-USER-SERVICE-SERVICE
cloud:
nacos:
discovery:
server-addr: qw.hungraim.com:31158
namespace: 74494ee6-1c9c-4165-97d2-d876f4b4befc
config:
namespace: 74494ee6-1c9c-4165-97d2-d876f4b4befc
server-addr: qw.hungraim.com:31158
file-extension: yaml # 必须修改成yaml
extension-configs:
- data-id: ism-database.yaml
group: common
refresh: true
- data-id: ism-basic.yaml
group: common
refresh: true
- data-id: thread-config.yaml
group: system
refresh: true
server:
port: 8002
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment