更新master

This commit is contained in:
yexuejc 2019-07-27 11:46:56 +08:00
parent 09f2138327
commit 4cdc2b631c
56 changed files with 3304 additions and 202 deletions

View File

@ -1,6 +1,18 @@
yexuejc-springboot 更新内容
-------------------
#### version 1.2.1
**time2019-7-27 09:39:24** <br/>
**branch** master <br/>
**关联工程:** <br/>
```
springboot-base:1.3.9
spring-boot-starter-parent:1.5.16.RELEASE
```
**update** <br/>
1. 所有自动装配增加开关,默认不装配。装配方式请参考[本项目自动装配开关](doc/plugin/AutoConfigure.md)
#
#### version 1.2.0
**time2018-12-1 12:19:06** <br/>
**branch** master <br/>

265
2.x-update.md Normal file
View File

@ -0,0 +1,265 @@
yexuejc-springboot 更新内容
-------------------
#### version 2.1.0
**time2019-7-24 18:30:49** <br/>
**branch** master <br/>
**关联工程:** <br/>
```
springboot-base:1.3.9
spring-boot-starter-parent:2.0.5.RELEASE
```
**update** <br/>
1. 所有自动装配增加开关,默认不装配。装配方式请参考[本项目自动装配开关](doc/plugin/AutoConfigure.md)
#
#### version 2.0.6
**time2019年4月2日21:08:453** <br/>
**branch** master <br/>
**关联工程:** <br/>
```
springboot-base:1.3.9
spring-boot-starter-parent:2.0.5.RELEASE
```
**update** <br/>
1. 升级依赖
2. 出入参加密 ParamsRequestBodyAdvice/ParamsResponseBodyAdvice 增加开关(默认关)
#
#### version 2.0.5
**time2018-12-1 12:27:10** <br/>
**branch** master <br/>
**关联工程:** <br/>
```
springboot-base:1.2.4
spring-boot-starter-parent:2.0.5.RELEASE
```
**update** <br/>
1. security多方登录第一个稳定版<br/>
支持账号登录、短信登录、第三方授权openid登录<br/>
功能链接[security重构-多方登录](doc/SECURITY.md)
#
#### version 2.0.3
**time2018-11-9 16:58:06** <br/>
**branch** master <br/>
**关联工程:** <br/>
```
springboot-base:1.2.1
spring-boot-starter-parent:2.0.5.RELEASE
```
**update** <br/>
1. 集成springboot security 多方登录
2. 文档拆分
#
#### version 2.0.2
**time2018-10-27 16:42:08** <br/>
**branch** master <br/>
**关联工程:** <br/>
```
springboot-base:1.2.0
spring-boot-starter-parent:2.0.5.RELEASE
```
**update** <br/>
1. 日志优化,按天切割日志<br>
内置 <br>
LogUtil.accessLogger.info(xxxx);请求访问控制级别info[LogInterceptor->line39](com.yexuejc.springboot.base.interceptor.LogInterceptor)<br>
LogUtil.bizLogger.info(xxxx); 业务日志级别trace<br>
LogUtil.exceptionLogger.error(xxxx);异常日志级别error<br>
```$xslt
日志配置置于application.properties
详情参考 logback-spring.xml
#日志contextName
spring.application.name=@pom.artifactId@
#日志级别
logging.level.root=info
#日志输出目录
logging.path=/logs/yexuejc-springboot-parent
```
#
#### version 2.0.1
**time2018-9-28 15:25:30** <br/>
**branch** 2.x <br/>
**关联工程:** <br/>
```
springboot-base:1.1.9
spring-boot-starter-parent:2.0.5.RELEASE
```
**update** <br/>
1. 新增声明包
#
#### version 2.0.0
**time2018-9-26 16:55:00** <br/>
**branch** 2.x <br/>
**关联工程:** <br/>
```
springboot-base:1.1.9
spring-boot-starter-parent:2.0.5.RELEASE
```
**update** <br/>
1. 升级依赖
2. 2.x分支将基于springboot 2.x 开发
#
#### version 1.1.0
**time2018-9-23 12:49:36** <br/>
**branch** master <br/>
**关联工程:** <br/>
```
springboot-base:1.1.9
spring-boot-starter-parent:1.5.15.RELEASE
```
**update** <br/>
1. 升级依赖
2. 增加SSL证书忽略默认关闭
3. 本版本更新工具依赖[https://github.com/yexuejc/yexuejc-base.git](https://github.com/yexuejc/yexuejc-base.git)不向下兼容
#
#### version 1.0.15
**time2018-9-3 19:29:39** <br/>
**branch** master <br/>
**关联工程:** <br/>
```
springboot-base:1.1.8
spring-boot-starter-parent:1.5.15.RELEASE
```
**update** <br/>
1. 升级依赖
#
#### version 1.0.14
**time2018-8-25 14:31:05** <br/>
**branch** master <br/>
**关联工程:** <br/>
```
springboot-base:1.1.7
spring-boot-starter-parent:1.5.15.RELEASE
```
**update** <br/>
1. 升级依赖
2. 优化拦截规则:增加通配符 /**
#
#### version 1.0.13
**time2018-8-17 11:41:18** <br/>
**branch** master <br/>
**关联工程:** <br/>
```
springboot-base:1.1.7
```
**update** <br/>
1. 升级base
#
#### version 1.0.12
**time2018-6-19 22:18:03** <br/>
**branch** master <br/>
**关联工程:** <br/>
```
springboot-base:1.1.6
```
**update** <br/>
1. maven仓库更新
#
#### version 1.0.11
**time2018-6-19 22:18:03** <br/>
**branch** master <br/>
**update** <br/>
1. 更新springboot-base:1.1.5依赖
#
#### version 1.0.10
**time2018年6月14日22:31:18** <br/>
**branch** master <br/>
**update** <br/>
1. 更新springboot-base:1.1.4依赖
2. 统一编码UTF-8
#
#### version 1.0.9
**time2018年6月2日12:17:18** <br/>
**branch** master <br/>
**update** <br/>
1. 更新base依赖
#
#### version 1.0.8
**time** 2018-5-4 09:54:18<br/>
**branch** master <br/>
**update** <br/>
1. 修复依赖
2. 使用加密:配置密钥方式/配置密钥方式 二选一
```
#加密开关
yexuejc.http.encrypt.encrypt=true
yexuejc.http.encrypt.decrypt=true
#配置密钥方式
yexuejc.http.encrypt.private-key=私钥
#配置证书方式
yexuejc.http.encrypt.private-key-path=/lgfishing.keystore 路径
yexuejc.http.encrypt.private-alias=别名
yexuejc.http.encrypt.private-pwd=密码
```
#
##### version 1.0.7
**time** 2018-5-4 09:54:18<br/>
**branch** master <br/>
**update** <br/>
>1. 新增加密证书配置
>2. RSA迁移到[yexuejc-base:1.1.1](https://github.com/yexuejc/yexuejc-base)工程
#
##### version 1.0.6 ~~1.0.5~~
**【change:2018-5-15 09:24:37】** 1.0.5 jitpack打包失败升级版本1.0.6<br/>
**time** 2018-5-4 09:54:18<br/>
**branch** master <br/>
**update** <br/>
> [使用加密解密](doc/PARAMS_RSA_DECRYPT_ENCRYPT.md)
>
>1.增加json入参解密、出参加密
#
##### version 1.0.4
**time** 2018-5-4 09:54:18<br/>
**branch** master <br/>
**update** <br/>
>1.更新springboot至1.5.12.RELEASE
#
#### version 1.0.3
**time** 2018-4-9 15:24:13<br/>
**branch** master <br/>
**update** <br/>
>1.变更包名
#
#### version 1.0.2
**time** 2018-4-1 17:00:15<br/>
**env** prod <br/>
**update** <br/>
>1.修复工具包ApiVO
#
#### version 0.0.2
**time** 2018-1-31 13:48:34<br/>
**env** ivt <br/>
**update** <br/>
>1.集成日志【security】
#
##### version 0.0.1
**time** 2018-1-31 12:16:10<br/>
**env** ivt <br/>
**update** <br/>
>1.第一次上传,集成通用环境
#

View File

@ -2,7 +2,7 @@
### 说明
>基于springboot版本分别维护1.x(对应springboot1.5.16.RELEASE) 2.x(对应springboot2.0.5.RELEASE) 分支 <br>
>master将继续同步1.x分支后期获取会同步于2.x
>master不再提供源代码,源代码请到具体分支中查看
#### 项目介绍
@ -13,9 +13,9 @@ parent版本封装<br/>
base:功能封装
#### 最新版本
* 1.x yexuejc.springboot.version=1.2.0 <br>
* 2.x yexuejc.springboot.version=2.0.5 <br>
* yexuejc.base.version=1.2.4
* 1.x yexuejc.springboot.version=1.2.1 <br>
* 2.x yexuejc.springboot.version=2.1.0 <br>
* yexuejc.base.version=1.3.9
pom.xml
```
@ -105,7 +105,10 @@ pom.xml
#### 版本更新
持续集成中...
<br/>
集成到自己项目前请先阅读文档,或者先运行示例工程
[更新记录](UPDATE.md)
更新记录: [1.x](1.x-update.md)、[2.x](2.x-update.md)
<br/>
[相关功能使用指南](doc/MENU.md)

View File

@ -1,7 +1,7 @@
功能目录
------------------------
### 第三方集成
### 第三方集成 -> [第三方集成具体使用](plugin/AutoConfigure.md)
#
* [redis 集成](REDIS.md)
* [Aliyun MNS 消息队列](MNS.md)
@ -10,6 +10,6 @@
### 内部集成
#
* [1.2.0/2.0.5 集成security登录第一个稳定版](SECURITY.md)
单独使用例子工程:[https://github.com/yexuejc/springboot-security-login-simple](https://github.com/yexuejc/springboot-security-login-simple)
* [1.0.6新增 针对API请求安全解决方案](PARAMS_RSA_DECRYPT_ENCRYPT.md)<br/>
* [1.0.6新增 加密功能](PARAMS_RSA_DECRYPT_ENCRYPT.md)

View File

@ -1,22 +1,22 @@
#生成私钥
keytool -genkey -alias lgfishing -keyalg RSA -keystore lgfishing2.keystore -keysize 1024 -validity 36500
keytool -genkey -alias test -keyalg RSA -keystore test.keystore -keysize 1024 -validity 36500
```
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
[Unknown]: heikengdiaoyu.com
[Unknown]: 1107047387@qq.com
您的组织单位名称是什么?
[Unknown]: 深圳金大米网络科技有限公司-老G钓鱼
[Unknown]: yexuejc
您的组织名称是什么?
[Unknown]: 成都极致思维网络科技有限公司-老G钓鱼
[Unknown]: 成都极致思维网络科技有限公司
您所在的城市或区域名称是什么?
[Unknown]: 成都
您所在的省/市/自治区名称是什么?
[Unknown]: 四川
该单位的双字母国家/地区代码是什么?
[Unknown]: CN
CN=heikengdiaoyu.com, OU=深圳金大米网络科技有限公司-老G钓鱼, O=成都极致思维网络科技有限公司-老G钓鱼, L=成都, ST=四川, C=CN是否正确?
CN=1107047387@qq.com, OU=yexuejc, O=成都极致思维网络科技有限公司, L=成都, ST=四川, C=CN是否正确?
[否]: 是
```
#生成公钥
keytool -export -alias lgfishing -keystore lgfishing2.keystore -storepass lgfishing2018 -rfc -file lgfishing2.cer
keytool -export -alias test -keystore test.keystore -storepass test2018 -rfc -file test2018.cer

View File

@ -0,0 +1,95 @@
本项目自动装配开关
---------------------
## 说明
本项目从2.1.0开始所有自动装配的功能增加开关控制,默认插件功能关闭.
开启需要在使用项目`application.properties`中增加`yexuejc.autoconfigure.mns.enable=true`类似的配置每一个插件功能key不一样
### 插件功能
注:使用阿里系的功能请引入阿里基础包
```
<!-- 阿里云基础SDK -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<optional>true</optional>
</dependency>
```
#### 阿里云MNS功能
> 类:[MnsAutoConfiguration](../../yexuejc-springboot-base/src/main/java/com/yexuejc/springboot/base/autoconfigure/MnsAutoConfiguration.java)
> <br/> 功能开关:`yexuejc.autoconfigure.mns.enable=true`
> <br/> 依赖:`MNSClient.class`
> <br/> pom 引入
> ```
> <!-- 阿里云消息服务MNS相关SDK -->
> <dependency>
> <groupId>com.aliyun.mns</groupId>
> <artifactId>aliyun-sdk-mns</artifactId>
> <classifier>jar-with-dependencies</classifier>
> <optional>true</optional>
> </dependency>
> ```
>application.properties 配置
>```
> yexuejc.alibaba.mns.access-key-id=自己到阿里云申请access-key
> yexuejc.alibaba.mns.access-key-secret=自己到阿里云申请access-key-secret
> yexuejc.alibaba.mns.endpoint=自己阿里云的endpoint
> yexuejc.alibaba.mns.queue-name-prefix=mns前缀
>```
#### redis 多database 配置
> 类:[MutiRedisAutoConfiguration](../../yexuejc-springboot-base/src/main/java/com/yexuejc/springboot/base/autoconfigure/MutiRedisAutoConfiguration.java)
> <br/> 功能开关:`yexuejc.autoconfigure.redis.enable=true`
> <br/> 依赖:`JedisConnection.class`, `RedisOperations.class`, `Jedis.class`
> <br/> pom 引入
> ```
> <!-- 使用Redis -->
> <dependency>
> <groupId>org.springframework.data</groupId>
> <artifactId>spring-data-redis</artifactId>
> <optional>true</optional>
> </dependency>
> <dependency>
> <groupId>redis.clients</groupId>
> <artifactId>jedis</artifactId>
> <optional>true</optional>
> </dependency>
> ```
>application.properties 配置
><br/> 默认db0k开启 1-15需要使用哪个`yexuejc.redis.dbx=true`
>```
> yexuejc.redis.db1=true
> spring.redis.jedis.pool.max-active=100
> spring.redis.jedis.pool.max-idle=10
> spring.redis.jedis.pool.min-idle=3
> spring.redis.host=地址
> spring.redis.password=密码
> spring.redis.port=端口
>```
#### 阿里 OSS 功能
> 类:[OssAutoConfiguration](../../yexuejc-springboot-base/src/main/java/com/yexuejc/springboot/base/autoconfigure/OssAutoConfiguration.java)
> <br/> 功能开关:`yexuejc.autoconfigure.oss.enable=true`
> <br/> 依赖:`OSSClient`
> <br/> pom 引入
> ```
> <!-- 阿里云OSS相关SDK -->
> <dependency>
> <groupId>com.aliyun.oss</groupId>
> <artifactId>aliyun-sdk-oss</artifactId>
> <optional>true</optional>
> </dependency>
> ```
>application.properties 配置
>```
> yexuejc.alibaba.oss.endpoint=自己去阿里申请的endpoint
> yexuejc.alibaba.oss.access-key-secret=自己到阿里云申请access-key-secret
> yexuejc.alibaba.oss.access-key-id=自己到阿里云申请access-key
> yexuejc.alibaba.oss.bucket=自己去阿里申请的bucket
>```
#### WebMvc 相关配置
> 类:[WebAutoConfiguration](../../yexuejc-springboot-base/src/main/java/com/yexuejc/springboot/base/autoconfigure/WebAutoConfiguration.java)
> <br/> 功能开关:`yexuejc.autoconfigure.webmvc.enable=true`
> 本类开启后的具体使用说明参见[WebMvc相关配置](WebAutoConfiguration.md)

View File

@ -0,0 +1,2 @@
WebMvc相关配置 [WebAutoConfiguration](../../yexuejc-springboot-base/src/main/java/com/yexuejc/springboot/base/autoconfigure/WebAutoConfiguration.java)
------------------------------------

19
pom.xml
View File

@ -5,7 +5,7 @@
<groupId>com.yexuejc.springboot</groupId>
<artifactId>yexuejc-springboot-parent</artifactId>
<version>1.2.0</version>
<version>2.1.0</version>
<packaging>pom</packaging>
<name>${project.artifactId}</name>
@ -15,12 +15,18 @@
<!-- spring boot父级,包含了统一版本管理,统一插件管理等 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.16.RELEASE</version>
<!-- <relativePath/> lookup parent from repository -->
<version>2.0.5.RELEASE</version>
<!--<relativePath/>-->
<!--lookup parent from repository-->
</parent>
<modules>
<module>yexuejc-springboot-base</module>
</modules>
<properties>
<yexuejc.base.version>1.2.4</yexuejc.base.version>
<yexuejc.base.version>1.3.9</yexuejc.base.version>
<repos.yexuejc.url>https://nexus.yexuejc.club/repository/</repos.yexuejc.url>
<repos.aliyun.url>http://maven.aliyun.com/nexus/content/groups/public</repos.aliyun.url>
@ -69,7 +75,7 @@
<!--<version>${yexuejc.base.version}</version>-->
<!--</dependency>-->
<dependency>
<groupId>com.yexuejc.base</groupId>
<groupId>top.yexuejc</groupId>
<artifactId>yexuejc-base</artifactId>
<version>${yexuejc.base.version}</version>
</dependency>
@ -304,7 +310,4 @@
</snapshotRepository>
</distributionManagement>
<modules>
<module>yexuejc-springboot-base</module>
</modules>
</project>

View File

@ -9,9 +9,9 @@
<parent>
<groupId>com.yexuejc.springboot</groupId>
<artifactId>yexuejc-springboot-parent</artifactId>
<version>1.2.0</version>
<version>2.1.0</version>
<!-- 本地打包:使用相对关联路径 -->
<!--<relativePath>../../yexuejc</relativePath>-->
<!--<relativePath>../</relativePath>-->
</parent>
<name>${project.artifactId}</name>
@ -23,7 +23,7 @@
<dependencies>
<!--基础包-->
<dependency>
<groupId>com.yexuejc.base</groupId>
<groupId>top.yexuejc</groupId>
<artifactId>yexuejc-base</artifactId>
</dependency>
<!--<dependency>-->

View File

@ -1,13 +1,13 @@
package com.yexuejc.springboot.base.autoconfigure;
import com.aliyun.mns.client.MNSClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.aliyun.mns.client.MNSClient;
/**
* 阿里云消息服务MNS相关配置
*
@ -20,6 +20,7 @@ import com.aliyun.mns.client.MNSClient;
@Configuration
@ConditionalOnClass(MNSClient.class)
@EnableConfigurationProperties(MnsProperties.class)
@ConditionalOnProperty(name = "yexuejc.autoconfigure.mns.enable", matchIfMissing = false)
public class MnsAutoConfiguration {
private final MnsProperties properties;

View File

@ -1,22 +1,19 @@
package com.yexuejc.springboot.base.autoconfigure;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Cluster;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Sentinel;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnection;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
@ -24,32 +21,24 @@ import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
/**
* 对redis封装
* 多个database配置
*
* @author maxf
* @version 1.0
* @ClassName MutiRedisAutoConfiguration
* @PackageName com.yexuejc.springboot.base.autoconfigure
* @Description
* @date 2018/11/1 10:31
* @date 2018/9/26 15:27
*/
@Configuration
@ConditionalOnClass({JedisConnection.class, RedisOperations.class, Jedis.class})
@EnableConfigurationProperties(RedisProperties.class)
@Order(1)
@ConditionalOnProperty(name = "yexuejc.autoconfigure.redis.enable", matchIfMissing = false)
public class MutiRedisAutoConfiguration {
public static final String BEAN_REDIS_FACTORY0 = "redisConnectionFactory";
public static final String BEAN_REDIS_TEMPLATE0 = "redisTemplate";
public static final String BEAN_REDIS_STRING_TEMPLATE0 = "stringRedisTemplate";
@ -82,207 +71,94 @@ public class MutiRedisAutoConfiguration {
public static final String BEAN_REDIS_TEMPLATE9 = "redis-template-9";
public static final String BEAN_REDIS_STRING_TEMPLATE9 = "redis-string-template-9";
/**
* Redis connection configuration.
*/
@Configuration
@ConditionalOnClass(GenericObjectPool.class)
protected static class RedisConnectionConfiguration {
private final RedisProperties properties;
private final RedisSentinelConfiguration sentinelConfiguration;
private final RedisClusterConfiguration clusterConfiguration;
public RedisConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,
ObjectProvider<RedisClusterConfiguration> clusterConfiguration) {
public RedisConnectionConfiguration(RedisProperties properties) {
this.properties = properties;
this.sentinelConfiguration = sentinelConfiguration.getIfAvailable();
this.clusterConfiguration = clusterConfiguration.getIfAvailable();
}
@Primary
@Bean(BEAN_REDIS_FACTORY0)
@ConditionalOnProperty(name = "yexuejc.redis.db0", matchIfMissing = true)
public JedisConnectionFactory redisConnectionFactory0() throws UnknownHostException {
return applyProperties(createJedisConnectionFactory(), 0);
return createJedisConnectionFactory(0);
}
@Bean(BEAN_REDIS_FACTORY1)
@ConditionalOnProperty(name = "yexuejc.redis.db1")
public JedisConnectionFactory redisConnectionFactory1() throws UnknownHostException {
return applyProperties(createJedisConnectionFactory(), 1);
return createJedisConnectionFactory(1);
}
@Bean(BEAN_REDIS_FACTORY2)
@ConditionalOnProperty(name = "yexuejc.redis.db2")
public JedisConnectionFactory redisConnectionFactory2() throws UnknownHostException {
return applyProperties(createJedisConnectionFactory(), 2);
return createJedisConnectionFactory(2);
}
@Bean(BEAN_REDIS_FACTORY3)
@ConditionalOnProperty(name = "yexuejc.redis.db3")
public JedisConnectionFactory redisConnectionFactory3() throws UnknownHostException {
return applyProperties(createJedisConnectionFactory(), 3);
return createJedisConnectionFactory(3);
}
@Bean(BEAN_REDIS_FACTORY4)
@ConditionalOnProperty(name = "yexuejc.redis.db4")
public JedisConnectionFactory redisConnectionFactory4() throws UnknownHostException {
return applyProperties(createJedisConnectionFactory(), 4);
return createJedisConnectionFactory(4);
}
@Bean(BEAN_REDIS_FACTORY5)
@ConditionalOnProperty(name = "yexuejc.redis.db5")
public JedisConnectionFactory redisConnectionFactory5() throws UnknownHostException {
return applyProperties(createJedisConnectionFactory(), 5);
return createJedisConnectionFactory(5);
}
@Bean(BEAN_REDIS_FACTORY6)
@ConditionalOnProperty(name = "yexuejc.redis.db6")
public JedisConnectionFactory redisConnectionFactory6() throws UnknownHostException {
return applyProperties(createJedisConnectionFactory(), 6);
return createJedisConnectionFactory(6);
}
@Bean(BEAN_REDIS_FACTORY7)
@ConditionalOnProperty(name = "yexuejc.redis.db7")
public JedisConnectionFactory redisConnectionFactory7() throws UnknownHostException {
return applyProperties(createJedisConnectionFactory(), 7);
return createJedisConnectionFactory(7);
}
@Bean(BEAN_REDIS_FACTORY8)
@ConditionalOnProperty(name = "yexuejc.redis.db8")
public JedisConnectionFactory redisConnectionFactory8() throws UnknownHostException {
return applyProperties(createJedisConnectionFactory(), 8);
return createJedisConnectionFactory(8);
}
@Bean(BEAN_REDIS_FACTORY9)
@ConditionalOnProperty(name = "yexuejc.redis.db9")
public JedisConnectionFactory redisConnectionFactory9() throws UnknownHostException {
return applyProperties(createJedisConnectionFactory(), 9);
return createJedisConnectionFactory(9);
}
protected final JedisConnectionFactory applyProperties(JedisConnectionFactory factory, int database) {
configureConnection(factory);
if (this.properties.isSsl()) {
factory.setUseSsl(true);
}
factory.setDatabase(database);
if (this.properties.getTimeout() > 0) {
factory.setTimeout(this.properties.getTimeout());
}
private JedisConnectionFactory createJedisConnectionFactory(int database) {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(properties.getHost());
redisStandaloneConfiguration.setPort(properties.getPort());
redisStandaloneConfiguration.setDatabase(database);
redisStandaloneConfiguration.setPassword(RedisPassword.of(properties.getPassword()));
JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfiguration = JedisClientConfiguration.builder();
JedisConnectionFactory factory = new JedisConnectionFactory(redisStandaloneConfiguration,
jedisClientConfiguration.build());
return factory;
}
private void configureConnection(JedisConnectionFactory factory) {
if (StringUtils.hasText(this.properties.getUrl())) {
configureConnectionFromUrl(factory);
} else {
factory.setHostName(this.properties.getHost());
factory.setPort(this.properties.getPort());
if (this.properties.getPassword() != null) {
factory.setPassword(this.properties.getPassword());
}
}
}
private void configureConnectionFromUrl(JedisConnectionFactory factory) {
String url = this.properties.getUrl();
if (url.startsWith("rediss://")) {
factory.setUseSsl(true);
}
try {
URI uri = new URI(url);
factory.setHostName(uri.getHost());
factory.setPort(uri.getPort());
if (uri.getUserInfo() != null) {
String password = uri.getUserInfo();
int index = password.lastIndexOf(":");
if (index >= 0) {
password = password.substring(index + 1);
}
factory.setPassword(password);
}
} catch (URISyntaxException ex) {
throw new IllegalArgumentException("Malformed 'spring.redis.url' " + url, ex);
}
}
protected final RedisSentinelConfiguration getSentinelConfig() {
if (this.sentinelConfiguration != null) {
return this.sentinelConfiguration;
}
Sentinel sentinelProperties = this.properties.getSentinel();
if (sentinelProperties != null) {
RedisSentinelConfiguration config = new RedisSentinelConfiguration();
config.master(sentinelProperties.getMaster());
config.setSentinels(createSentinels(sentinelProperties));
return config;
}
return null;
}
/**
* Create a {@link RedisClusterConfiguration} if necessary.
*
* @return {@literal null} if no cluster settings are set.
*/
protected final RedisClusterConfiguration getClusterConfiguration() {
if (this.clusterConfiguration != null) {
return this.clusterConfiguration;
}
if (this.properties.getCluster() == null) {
return null;
}
Cluster clusterProperties = this.properties.getCluster();
RedisClusterConfiguration config = new RedisClusterConfiguration(clusterProperties.getNodes());
if (clusterProperties.getMaxRedirects() != null) {
config.setMaxRedirects(clusterProperties.getMaxRedirects());
}
return config;
}
private List<RedisNode> createSentinels(Sentinel sentinel) {
List<RedisNode> nodes = new ArrayList<RedisNode>();
for (String node : StringUtils.commaDelimitedListToStringArray(sentinel.getNodes())) {
try {
String[] parts = StringUtils.split(node, ":");
Assert.state(parts.length == 2, "Must be defined as 'host:port'");
nodes.add(new RedisNode(parts[0], Integer.valueOf(parts[1])));
} catch (RuntimeException ex) {
throw new IllegalStateException("Invalid redis sentinel " + "property '" + node + "'", ex);
}
}
return nodes;
}
private JedisConnectionFactory createJedisConnectionFactory() {
JedisPoolConfig poolConfig = this.properties.getPool() != null ? jedisPoolConfig() : new JedisPoolConfig();
if (getSentinelConfig() != null) {
return new JedisConnectionFactory(getSentinelConfig(), poolConfig);
}
if (getClusterConfiguration() != null) {
return new JedisConnectionFactory(getClusterConfiguration(), poolConfig);
}
return new JedisConnectionFactory(poolConfig);
}
private JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig config = new JedisPoolConfig();
RedisProperties.Pool props = this.properties.getPool();
config.setMaxTotal(props.getMaxActive());
config.setMaxIdle(props.getMaxIdle());
config.setMinIdle(props.getMinIdle());
config.setMaxWaitMillis(props.getMaxWait());
return config;
}
}
/**
* Standard Redis configuration.
*/
@ -468,5 +344,4 @@ public class MutiRedisAutoConfiguration {
}
}
}

View File

@ -4,6 +4,7 @@ import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -20,6 +21,7 @@ import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnClass({OSSClient.class})
@EnableConfigurationProperties(OssProperties.class)
@ConditionalOnProperty(name = "yexuejc.autoconfigure.oss.enable", matchIfMissing = false)
public class OssAutoConfiguration {
private final OssProperties properties;

View File

@ -63,4 +63,5 @@ public class OssProperties {
this.bucket = bucket;
}
}

View File

@ -17,6 +17,7 @@ import com.yexuejc.springboot.base.filter.ValidationFilterProperties;
import com.yexuejc.springboot.base.interceptor.LogInterceptor;
import com.yexuejc.springboot.base.util.LogUtil;
import com.yexuejc.springboot.base.util.SSLUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@ -52,6 +53,7 @@ import java.util.List;
@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(ValidationFilterProperties.class)
@ConditionalOnProperty(name = "yexuejc.autoconfigure.webmvc.enable", matchIfMissing = false)
public class WebAutoConfiguration extends WebMvcConfigurerAdapter {
@ -61,6 +63,7 @@ public class WebAutoConfiguration extends WebMvcConfigurerAdapter {
/******************************************编码部分*****************************************************/
@Bean
@ConditionalOnMissingBean
public HttpMessageConverter<String> responseBodyConverter() {
StringHttpMessageConverter converter = new StringHttpMessageConverter(
Charset.forName("UTF-8"));
@ -68,6 +71,7 @@ public class WebAutoConfiguration extends WebMvcConfigurerAdapter {
}
@Bean
@ConditionalOnMissingBean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
@ -120,6 +124,7 @@ public class WebAutoConfiguration extends WebMvcConfigurerAdapter {
* @return
*/
@Bean
@ConditionalOnMissingBean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
@ -138,6 +143,7 @@ public class WebAutoConfiguration extends WebMvcConfigurerAdapter {
* @return
*/
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "yexuejc.web.validation-filter.enable", matchIfMissing = true)
public FilterRegistrationBean validationFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
@ -148,11 +154,12 @@ public class WebAutoConfiguration extends WebMvcConfigurerAdapter {
return registration;
}
@Bean
/**
* 是否开启HTTPSSSL请求证书验证忽略默认false
*/
@ConditionalOnProperty(name = "yexuejc.enable.ssl-ignore", matchIfMissing = false)
@ConditionalOnProperty(name = "yexuejc.ssl-ignore.enable", matchIfMissing = false)
@Bean
@ConditionalOnMissingBean
public SSLUtil getSslUtil() {
return new SSLUtil();
}
@ -161,6 +168,7 @@ public class WebAutoConfiguration extends WebMvcConfigurerAdapter {
* 全局异常处理
*/
@ControllerAdvice
@ConditionalOnProperty(name = "yexuejc.global.exception.enable", matchIfMissing = true)
static class GlobalExceptionHandler {
private static final String ERROR_MSG = "系统错误,请联系管理员";
@ -185,3 +193,5 @@ public class WebAutoConfiguration extends WebMvcConfigurerAdapter {
}
}

View File

@ -9,6 +9,7 @@ import com.yexuejc.springboot.base.exception.GatewayException;
import com.yexuejc.springboot.base.util.LogUtil;
import org.apache.commons.io.IOUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
@ -35,6 +36,7 @@ import java.security.interfaces.RSAPrivateKey;
@ControllerAdvice
@ConditionalOnClass({RequestBodyAdvice.class, HttpHeaders.class, HttpInputMessage.class, HttpMessageConverter.class})
@EnableConfigurationProperties(RsaProperties.class)
@ConditionalOnProperty(value = "yexuejc.filter.req.enable", matchIfMissing = false)
public class ParamsRequestBodyAdvice implements RequestBodyAdvice {
private final RsaProperties properties;
@ -49,12 +51,25 @@ public class ParamsRequestBodyAdvice implements RequestBodyAdvice {
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<?
extends HttpMessageConverter<?>> converterType) {
return body;
}
/**
* 使用入参加密
* 自定义入参的解密方式只需要重写 beforeBodyRead 方法即可
*
* @param inputMessage
* @param parameter
* @param targetType
* @param converterType
* @return
* @throws IOException
*/
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<?
extends HttpMessageConverter<?>> converterType) throws IOException {
if (properties.isDecrypt()) {
ParamsPO paramsPO = JsonUtil.json2Obj(IOUtils.toString(inputMessage.getBody(), "UTF-8"), ParamsPO.class);
//RSA解密
@ -63,7 +78,8 @@ public class ParamsRequestBodyAdvice implements RequestBodyAdvice {
RSAPrivateKey rsaPrivateKey = null;
if (StrUtil.isEmpty(properties.getPrivateKey())) {
rsaPrivateKey = RSA2.getPrivateKey(
this.getClass().getResource(properties.getPrivateKeyPath()).getFile().toString(),
// this.getClass().getResource(properties.getPrivateKeyPath()).getFile().toString(),
this.getClass().getResourceAsStream(properties.getPrivateKeyPath()),
properties.getPrivateAlias(),
properties.getPrivatePwd());
} else {
@ -92,7 +108,8 @@ public class ParamsRequestBodyAdvice implements RequestBodyAdvice {
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<?
extends HttpMessageConverter<?>> converterType) {
return body;
}

View File

@ -7,6 +7,7 @@ import com.yexuejc.base.util.JsonUtil;
import com.yexuejc.base.util.StrUtil;
import com.yexuejc.springboot.base.util.LogUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
@ -32,6 +33,7 @@ import java.util.Map;
@ControllerAdvice
@ConditionalOnClass({ResponseBodyAdvice.class, ServerHttpRequest.class, ServerHttpResponse.class, MediaType.class})
@EnableConfigurationProperties(RsaProperties.class)
@ConditionalOnProperty(value = "yexuejc.filter.resp.enable", matchIfMissing = false)
public class ParamsResponseBodyAdvice implements ResponseBodyAdvice {
private final RsaProperties properties;
@ -47,7 +49,8 @@ public class ParamsResponseBodyAdvice implements ResponseBodyAdvice {
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
if (returnType.getMethod().isAnnotationPresent(SerializedField.class)) {
//获取注解配置的包含和去除字段
SerializedField serializedField = returnType.getMethodAnnotation(SerializedField.class);
@ -74,7 +77,8 @@ public class ParamsResponseBodyAdvice implements ResponseBodyAdvice {
RSAPrivateKey rsaPrivateKey = null;
if (StrUtil.isEmpty(properties.getPrivateKey())) {
rsaPrivateKey = RSA2.getPrivateKey(
this.getClass().getResource(properties.getPrivateKeyPath()).getFile().toString(),
// this.getClass().getResource(properties.getPrivateKeyPath()).getFile().toString(),
this.getClass().getResourceAsStream(properties.getPrivateKeyPath()),
properties.getPrivateAlias(),
properties.getPrivatePwd());
} else {

View File

@ -5,28 +5,46 @@ spring.application.name=@pom.artifactId@
logging.level.root=info
logging.path=/logs/yexuejc-springboot-parent
#========================================================================================================================
#========================================================================================================================
#核心
#开启功能 redis webmvc
yexuejc.autoconfigure.redis.enable=true
#webmvc 包含以下功能
yexuejc.autoconfigure.webmvc.enable=true
#全局异常处理
yexuejc.ssl-ignore.enable=true
#开启HTTPSSSL请求证书验证忽略
yexuejc.global.exception.enable=true
#开启校验过滤器目前校验HTTP Header是否符合规范
yexuejc.web.validation-filter.enable=true
# 拦截类型请求路径0忽略模式默认拦截全部1拦截模式默认一个都不拦截
#yexuejc.http.filter=0
yexuejc.http.filter.type=1
#忽略路径示例放开swagger
#yexuejc.http.filter.ignored=/,/swagger/**,/error,/v2/api-docs,/webjars/**
#========================================================================================================================
#========================================================================================================================
yexuejc.http.encrypt.encrypt=true
yexuejc.http.encrypt.decrypt=true
#配置密钥方式
#配置密钥方式
#yexuejc.http.encrypt.private-key=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAiSo5blJ9-QJ0_QElcy5AaRTq-3oO4lJ8PvIOIt-Xr5SUFODVj3DUbiy6_0bxQYO3NiYHlXPb37UVV3jjlXJsXwIDAQABAkBE0WOJH2hGs93gRl_0vwLf9ffDfkTTdlER_73p70aad3QZRslEkinQH7G5aE_DgBm5m72TCeH-PD2FZ2lwtavBAiEAvnRown5Lpqbl0tN_OUxr_e1u9d_-8dNL_JEETO7BZCECIQC4XtY-18j0bVVLxaXPjKQ00D59yntwObihDNyRK0nAfwIgHPHEGgrnpGQo-Wl7JFIg925mNqfcLxRVsAS6CpcefQECIQCUsLdsmy6QIhTmNRJSXoSXq1KatE_05DhIekzwLs8eFQIgfMawMiu52ZxBI5_pZ7ancQZ6Dsxl45utFqJShzV1pio
#yexuejc.http.encrypt.public-key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIkqOW5SffkCdP0BJXMuQGkU6vt6DuJSfD7yDiLfl6-UlBTg1Y9w1G4suv9G8UGDtzYmB5Vz29-1FVd445VybF8CAwEAAQ
#配置证书方式
#配置证书方式
yexuejc.http.encrypt.private-key-path=/lgfishing.keystore
yexuejc.http.encrypt.private-alias=lgfishing
yexuejc.http.encrypt.private-pwd=lgfishing2018
#编码
#编码
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
server.tomcat.uri-encoding=UTF-8
#是否开启HTTPSSSL请求证书验证忽略默认false
#是否开启HTTPSSSL请求证书验证忽略默认false
yexuejc.enable.ssl-ignore=true
@ -48,9 +66,9 @@ yexuejc.alibaba.oss.bucket=guansichou
#========================================================================================================================
# security相关
# security相关
#reids
#开启指定redis库db0默认开启
#开启指定redis库db0默认开启
yexuejc.redis.db1=true
spring.redis.jedis.pool.max-active=100
spring.redis.jedis.pool.max-idle=10
@ -75,19 +93,19 @@ spring.datasource.data=classpath:db/data.sql
#========================================================================================================================
#mybatis-plus
mybatis-plus.mapper-locations=classpath*:mapper/*.xml
#实体扫描多个package用逗号或者分号分隔
#实体扫描多个package用逗号或者分号分隔
mybatis-plus.type-aliases-package=com.yexuejc.springboot.base.security.domain
#主键类型0:"数据库ID自增", 1:"用户输入ID",2:"该类型为未设置主键类型", 3:"全局唯一ID UUID",4:全局唯一ID (UUID),5:字符串全局唯一ID (idWorker 的字符串表示);
#主键类型0:"数据库ID自增", 1:"用户输入ID",2:"该类型为未设置主键类型", 3:"全局唯一ID UUID",4:全局唯一ID (UUID),5:字符串全局唯一ID (idWorker 的字符串表示);
mybatis-plus.global-config.db-config.id-type=uuid
mybatis-plus.global-config.db-config.db-type=POSTGRE_SQL
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
mybatis-plus.global-config.db-config.field-strategy=not_empty
#驼峰下划线转换
#驼峰下划线转换
mybatis-plus.global-config.db-config.column-underline=true
#逻辑删除配置下面3个配置
#逻辑删除配置下面3个配置
mybatis-plus.global-config.db-config.logic-delete-value=true
mybatis-plus.global-config.db-config.logic-not-delete-value=false
#配置返回数据库(column下划线命名&&返回java实体是驼峰命名)自动匹配无需as没开启这个SQL需要写as select user_id as userId
#配置返回数据库(column下划线命名&&返回java实体是驼峰命名)自动匹配无需as没开启这个SQL需要写as select user_id as userId
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.cache-enabled=false
#========================================================================================================================

View File

@ -0,0 +1,16 @@
<?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>
<groupId>com.yexuejc.springboot</groupId>
<version>1.0.0</version>
<artifactId>yexuejc-springboot-example</artifactId>
<packaging>pom</packaging>
<name>yexuejc-springboot-example</name>
<modules>
<module>yexuejc-springboot-simple</module>
<module>springboot-security-login-simple</module>
</modules>
</project>

View File

@ -0,0 +1,27 @@
/target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
.mvn/wrapper/maven-wrapper.properties
.mvn/wrapper/maven-wrapper.jar

View File

@ -0,0 +1,245 @@
https://github.com/yexuejc/yexuejc-springboot 多方登录模块使用例子
---------------------------------------------------------------
#### 先上[效果图](Securtity效果图.md)
> **引入依赖 pom.xml**
```mxml
<dependency>
<groupId>com.yexuejc.springboot</groupId>
<artifactId>yexuejc-springboot-base</artifactId>
<version>最新版</version>
</dependency>
```
#### 所有核心文件都在 com.yexuejc.springboot.base.security 包下
#### 现附上系统实现逻辑图
![多方登录系统实现逻辑图](sl/多方登录设计.jpg)
1.com.yexuejc.springboot.base.security.SecurityConfig
<br/>
**Security 核心本文件并未启动Security需继承然后继承类上加上@EnableWebSecurity注解就启动Security了。**
* 实现loadUserByUsername()方法;自定义逻辑处理登录账号,返回登录账号相关信息
* 实现loginHodler()方法自定义处理登录成功filter.setAuthenticationSuccessHandler()和失败filter.setAuthenticationFailureHandler()的处理
* 继承configure(HttpSecurity http) 完善更多security过滤配置
* 例子[com.yexuejc.springboot.base.security.MySecurityConfig](../yexuejc-springboot-base/src/test/java/com/yexuejc/springboot/base/security/MySecurityConfig.java)
#### 注: 代码中抛出的相关异常拦截在filter.setAuthenticationFailureHandler()中处理,参考[MySecurityConfig](../yexuejc-springboot-base/src/test/java/com/yexuejc/springboot/base/security/MySecurityConfig.java)
```
filter.setAuthenticationFailureHandler((request, response, exception) -> {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpStatus.UNAUTHORIZED.value());
Resps resps = new Resps();
if (exception instanceof DisabledException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_IS_LOCK_MSG});
} else if (exception instanceof AccountExpiredException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_IS_EXPIRE_MSG});
} else if (exception instanceof CredentialsExpiredException) {
resps.setErr(BizConsts.BASE_LOGIN_IS_EXPIRE_CODE, new String[]{BizConsts.BASE_LOGIN_IS_EXPIRE_MSG});
} else if (exception instanceof LockedException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_IS_LOCKED_MSG});
} else if (exception instanceof AuthenticationCredentialsNotFoundException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_CREDENTIALS_NOT_FOUND_MSG});
} else if (exception instanceof ThirdPartyAuthorizationException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{exception.getMessage()});
} else if (exception instanceof BadCredentialsException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_PWD_IS_ERR_MSG});
} else if (exception instanceof UsernameNotFoundException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_ACCOUNT_NOT_FOUND_MSG});
} else if (exception instanceof UserNotAuthoriayException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{exception.getMessage()});
} else {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_SYS_ERR_MSG});
}
response.getWriter().write(JsonUtil.obj2Json(resps));
response.getWriter().close();
});
```
2.com.yexuejc.springboot.base.security.UserDetailsManager
<br/>
**获取登录用户信息**
* 需要实现com.yexuejc.springboot.base.security.inte.UserService
* 例子[com.yexuejc.springboot.base.security.UserServiceImpl](../yexuejc-springboot-base/src/test/java/com/yexuejc/springboot/base/security/UserServiceImpl.java)
3.com.yexuejc.springboot.base.security.LoginToken
<br/>
**登录成功封装至JWT的登录用户信息**
4.com.yexuejc.springboot.base.security.ConsumerUser
<br/>
**登录成功封装至redis的登录用户信息**
5.com.yexuejc.springboot.base.security.ConsumerToken
<br/>
**登录请求时(/login)用户登录参数信息**
6.com.yexuejc.springboot.base.security.ConsumerSecurityContextRepository
<br/>
**登录校验token正确性返回登录用户从redis中获取**
7.com.yexuejc.springboot.base.security.ConsumerAuthenticationProvider
<br/>
**登录时账号校验原为密码校验重写之后增加校验短信验证码第三方openid**
8.com.yexuejc.springboot.base.security.ConsumerAuthenticationProcessingFilter
<br/>
**重写登录拦截,集成多种登录方式到/login**
<h2>使用example</h2>
1. 下载本项目至本地找到yexuejc/yexuejc-springboot/yexuejc-springboot-base/src/test/java/com/yexuejc/springboot/base/ApplicationRun.java
至接run
2. 测试环境配置如下(测试运行环境都在test下面)<br/>
2.1 pom.xml<br/>
* mybatis-plus数据库框架
* HikariCP数据库连接池
* 本地数据库H2
* JJWT作为登录凭证token
* redis 存储登录用户信息
> 关于这些相关框架、工具不做详解,有兴趣可以去学习,这些都可以用你自己熟悉的替换
com.yexuejc.springboot版本请依赖最新版本
```
<parent>
<groupId>com.yexuejc.springboot</groupId>
<artifactId>yexuejc-springboot-parent</artifactId>
<version>2.0.3</version>
</parent>
<properties>
<yexuejc.base.version>1.2.1</yexuejc.base.version>
</properties>
<dependencies>
<!--base 引用-->
<dependency>
<groupId>com.yexuejc.springboot</groupId>
<artifactId>yexuejc-springboot-base</artifactId>
<version>${parent.version}</version>
</dependency>
<!--https://gitee.com/incloudcode/yexuejc-base.git-->
<dependency>
<groupId>com.yexuejc.base</groupId>
<artifactId>yexuejc-base</artifactId>
<version>${yexuejc.base.version}</version>
</dependency>
<!-- 使用springMVC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JJWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<optional>true</optional>
</dependency>
<!-- 使用Redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- HikariCP数据库连接池JDK1.8 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<!-- springboot mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- 内存数据库h2-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>yexuejc-nexus-public</id>
<name>yexuejc-nexus-public</name>
<url>https://nexus.yexuejc.club/repository/maven-public/</url>
</repository>
</repositories>
```
2.2 对应的application.properties<br/>
* redis 0库存储登录用户信息1库存储短信验证码
* H2数据库 创建数据库表 consumer(用户表) [schema.sql](../yexuejc-springboot-base/src/test/resources/db/schema.sql)
增加一条用户数据[data.sql](../yexuejc-springboot-base/src/test/resources/db/data.sql)
<br/>启动项目后会自动运行这两个脚本自此H2数据库中就会有一条用户数据测试时可以用来登录
<br/>PS:项目运行成功后可以访问 http://localhost:8888/h2-console 登录到数据库
* mybatis-plus 详情[http://mp.baomidou.com/](http://mp.baomidou.com/)
```
#========================================================================================================================
# security相关
#reids
#开启指定redis库db0默认开启
yexuejc.redis.db1=true
spring.redis.jedis.pool.max-active=100
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=3
spring.redis.host=121.42.165.89
spring.redis.password=
spring.redis.port=16379
#db
spring.h2.console.path=/h2-console
spring.h2.console.enabled=true
spring.h2.console.settings.web-allow-others=true
spring.datasource.username=sa
spring.datasource.password=123456
spring.datasource.url=jdbc:h2:mem:test;MODE=PostgreSQL
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.schema=classpath:db/schema.sql
spring.datasource.data=classpath:db/data.sql
#========================================================================================================================
#mybatis-plus
mybatis-plus.mapper-locations=classpath*:mapper/*.xml
#实体扫描多个package用逗号或者分号分隔
mybatis-plus.type-aliases-package=com.yexuejc.springboot.base.security.domain
#主键类型0:"数据库ID自增", 1:"用户输入ID",2:"该类型为未设置主键类型", 3:"全局唯一ID UUID",4:全局唯一ID (UUID),5:字符串全局唯一ID (idWorker 的字符串表示);
mybatis-plus.global-config.db-config.id-type=uuid
mybatis-plus.global-config.db-config.db-type=POSTGRE_SQL
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
mybatis-plus.global-config.db-config.field-strategy=not_empty
#驼峰下划线转换
mybatis-plus.global-config.db-config.column-underline=true
#逻辑删除配置下面3个配置
mybatis-plus.global-config.db-config.logic-delete-value=true
mybatis-plus.global-config.db-config.logic-not-delete-value=false
#配置返回数据库(column下划线命名&&返回java实体是驼峰命名)自动匹配无需as没开启这个SQL需要写as select user_id as userId
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.cache-enabled=false
#========================================================================================================================
```
> 附图
![security1.png](security1.png)
<br>
![security2.png](security2.png)
<br>
![security3.png](security3.png)

View File

@ -0,0 +1,24 @@
Security 多方登录封装使用效果图
---------------
### 账号登录
密码错误
![](sl/sl_02.png)
正确
![](sl/sl_01.png)
### 短信登录
发送短信
![](sl/sl_ss.png)
短信错误
![](sl/sl_err.jpg)
短信过期
![](sl/sl_gq.png)
正确
![](sl/sl_10.png)
### 第三方登录
第一次登录,需要绑定手机号
![](sl/sl_t3.png)
绑定过手机号的第三方账号登录(绑定相关业务需要自己实现)
![](sl/sl_t4.png)

View File

@ -0,0 +1,286 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
wget "$jarUrl" -O "$wrapperJarPath"
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
curl -o "$wrapperJarPath" "$jarUrl"
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

View File

@ -0,0 +1,161 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
echo Found %WRAPPER_JAR%
) else (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
echo Finished downloading %WRAPPER_JAR%
)
@REM End of extension
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%

View File

@ -0,0 +1,101 @@
<?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>
<groupId>com.yexuejc.springboot</groupId>
<artifactId>springboot-security-login-simple</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>springboot-security-login-simple</name>
<description>
https://gitee.com/incloudcode/yexuejc-springboot使用例子
</description>
<parent>
<groupId>com.yexuejc.springboot</groupId>
<artifactId>yexuejc-springboot-parent</artifactId>
<version>2.1.0</version>
</parent>
<properties>
<yexuejc.base.version>1.3.9</yexuejc.base.version>
</properties>
<dependencies>
<!--base 引用-->
<dependency>
<groupId>com.yexuejc.springboot</groupId>
<artifactId>yexuejc-springboot-base</artifactId>
<version>${parent.version}</version>
</dependency>
<!--https://gitee.com/incloudcode/yexuejc-base.git-->
<dependency>
<groupId>top.yexuejc</groupId>
<artifactId>yexuejc-base</artifactId>
<version>${yexuejc.base.version}</version>
</dependency>
<!-- 使用springMVC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JJWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<optional>true</optional>
</dependency>
<!-- 使用Redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- HikariCP数据库连接池JDK1.8 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<!-- springboot mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- 内存数据库h2-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>yexuejc-nexus-public</id>
<name>yexuejc-nexus-public</name>
<url>https://nexus.yexuejc.club/repository/maven-public/</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

View File

@ -0,0 +1,12 @@
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

View File

@ -0,0 +1,39 @@
package com.example.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.example.demo.security.domain.Consumer;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* <p>
* Mapper 接口
* </p>
*
* @author yexuejc
* @since 2018-05-27
*/
@Mapper
public interface ConsumerMapper extends BaseMapper<Consumer> {
/**
* <p>
* 插入一条记录
* </p>
*
* @param entity 实体对象
* @return int
*/
@Override
int insert(Consumer entity);
/**
* 修改权限
*
* @param entity
* @return
*/
Integer updateRoles(@Param(Constants.ENTITY) Consumer entity);
}

View File

@ -0,0 +1,53 @@
package com.example.demo.mapper.handler;
import com.yexuejc.base.util.JsonUtil;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 数据库查询转换 -> JSON
*/
@MappedTypes({Object.class})
public class JsonTypeHandler extends BaseTypeHandler<Object> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
throws SQLException {
if (parameter == null) {
ps.setString(i, null);
} else {
ps.setString(i, JsonUtil.obj2Json(parameter));
}
}
@Override
public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
if (rs.getString(columnName) == null) {
return null;
}
return JsonUtil.json2Obj(rs.getString(columnName), Object.class);
}
@Override
public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
if (rs.getString(columnIndex) == null) {
return null;
}
return JsonUtil.json2Obj(rs.getString(columnIndex), Object.class);
}
@Override
public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
if (cs.getString(columnIndex) == null) {
return null;
}
return JsonUtil.json2Obj(cs.getString(columnIndex), Object.class);
}
}

View File

@ -0,0 +1,224 @@
package com.example.demo.security;
import com.yexuejc.base.constant.RespsConsts;
import com.yexuejc.base.http.Resps;
import com.yexuejc.base.util.JsonUtil;
import com.yexuejc.base.util.JwtUtil;
import com.yexuejc.base.util.RegexUtil;
import com.yexuejc.base.util.StrUtil;
import com.yexuejc.springboot.base.autoconfigure.MutiRedisAutoConfiguration;
import com.yexuejc.springboot.base.constant.BizConsts;
import com.yexuejc.springboot.base.exception.ThirdPartyAuthorizationException;
import com.yexuejc.springboot.base.exception.UserNotAuthoriayException;
import com.yexuejc.springboot.base.security.ConsumerAuthenticationProcessingFilter;
import com.yexuejc.springboot.base.security.ConsumerUser;
import com.yexuejc.springboot.base.security.LoginToken;
import com.yexuejc.springboot.base.security.SecurityConfig;
import com.yexuejc.springboot.base.security.inte.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.*;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.context.SecurityContextRepository;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @author maxf
* @version 1.0
* @ClassName SecurityConfig
* @Description
* @date 2018/11/8 17:30
*/
@EnableWebSecurity(debug = false)
public class MySecurityConfig extends SecurityConfig {
@Autowired
@Qualifier("userserviceimpl")
UserService userService;
@Override
protected UserService getUserService() {
return userService;
}
@Autowired
@Qualifier(MutiRedisAutoConfiguration.BEAN_REDIS_TEMPLATE0)
private RedisTemplate<Object, Object> redisTemplate0;
@Override
protected RedisTemplate<Object, Object> getRedisDB() {
return redisTemplate0;
}
//自定义==================================================================
@Override
protected AuthenticationProvider createConsumerAuthenticationProvider(UserDetailsService userDetailsService) {
return super.createConsumerAuthenticationProvider(userDetailsService);
}
@Override
protected ConsumerAuthenticationProcessingFilter createConsumerAuthenticationProcessingFilter(AuthenticationManager authenticationManager) {
return super.createConsumerAuthenticationProcessingFilter(authenticationManager);
}
@Override
protected SecurityContextRepository createConsumerSecurityContextRepository() {
return super.createConsumerSecurityContextRepository();
}
@Override
protected UserDetailsService createUserDetailsManager() {
return super.createUserDetailsManager();
}
//自定义==================================================================
/**
* 保存登录信息至redis
*
* @param redisTemplate0 redis 链接
* @param user 登录用户
* @param roles 角色信息
* @param token 登录token
* @param isPast 是否设置过期
*/
private void saveLoginUser(RedisTemplate<Object, Object> redisTemplate0, ConsumerUser user, List<String> roles, String token,
boolean isPast) {
Map<String, Object> m = new HashMap<>(4);
m.put("username", user.getUsername());
m.put("token", token);
m.put("roles", roles);
m.put("id", user.getId());
m.put("logType", user.getLogType());
m.put("logTime", user.getLogTime());
redisTemplate0.opsForHash().putAll(BizConsts.CONSUMER_LOGIN_REDIS + "." + user.getUsername(), m);
if (isPast) {
//对于没有绑定手机号的token10分钟后过期
redisTemplate0.expire(BizConsts.CONSUMER_LOGIN_REDIS + "." + user.getUsername(), 10, TimeUnit.MINUTES);
}
}
/**
* <pre>
* 处理登录
* 成功: filter.setAuthenticationSuccessHandler()
* 失败: filter.setAuthenticationFailureHandler()
* </pre>
*
* @param filter
*/
@Override
protected void loginHodler(ConsumerAuthenticationProcessingFilter filter) {
filter.setAuthenticationSuccessHandler((request, response, authentication) -> {
String token = JwtUtil.instace().compact(new LoginToken(authentication.getName()));
ConsumerUser user = (ConsumerUser) authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
List<String> roles = new ArrayList<>();
if (authorities != null && authorities.size() > 0) {
for (GrantedAuthority g : authorities) {
roles.add(g.getAuthority());
}
}
Map<String, Object> map = new HashMap<>(2);
map.put("token", token);
map.put("bindMobile", false);
if (StrUtil.isEmpty(user.getUsername()) || !RegexUtil.regex(user.getUsername(), RegexUtil.REGEX_MOBILE)) {
map.put("bindMobile", true);
}
saveLoginUser(redisTemplate0, user, roles, token, (Boolean) map.get("bindMobile"));
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(JsonUtil.obj2Json(Resps.success().setSucc(map)));
response.getWriter().close();
});
filter.setAuthenticationFailureHandler((request, response, exception) -> {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpStatus.UNAUTHORIZED.value());
Resps resps = new Resps();
if (exception instanceof DisabledException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_IS_LOCK_MSG});
} else if (exception instanceof AccountExpiredException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_IS_EXPIRE_MSG});
} else if (exception instanceof CredentialsExpiredException) {
resps.setErr(BizConsts.BASE_LOGIN_IS_EXPIRE_CODE, new String[]{BizConsts.BASE_LOGIN_IS_EXPIRE_MSG});
} else if (exception instanceof LockedException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_IS_LOCKED_MSG});
} else if (exception instanceof AuthenticationCredentialsNotFoundException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_CREDENTIALS_NOT_FOUND_MSG});
} else if (exception instanceof ThirdPartyAuthorizationException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{exception.getMessage()});
} else if (exception instanceof BadCredentialsException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_PWD_IS_ERR_MSG});
} else if (exception instanceof UsernameNotFoundException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_ACCOUNT_NOT_FOUND_MSG});
} else if (exception instanceof UserNotAuthoriayException) {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{exception.getMessage()});
} else {
resps.setErr(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_SYS_ERR_MSG});
}
response.getWriter().write(JsonUtil.obj2Json(resps));
response.getWriter().close();
});
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.headers().frameOptions().disable();
/**
* 权限控制
* ->无权限
*/
http.authorizeRequests().antMatchers(
"/", "/index"
).permitAll();
/**
* 权限控制
* ->登录可访问
*/
http.authorizeRequests().antMatchers(
"/consumer/**", "/sms/bind/**").authenticated();
// 登出处理
http.logout().logoutSuccessHandler((request, response, authentication) -> {
redisTemplate0.delete(BizConsts.CONSUMER_LOGIN_REDIS + "." + authentication.getName());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(JsonUtil.obj2Json(Resps.success()));
response.getWriter().close();
});
// 未登录却访问需要登录的接口时的处理
http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(401);
response.getWriter().write(
JsonUtil.obj2Json(
Resps.error(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_NOT_LOGIN_MSG})
)
);
response.getWriter().close();
});
// 已登录但当前用户没有访问的某个接口的权限时的处理
http.exceptionHandling().accessDeniedHandler((request, response, accessDeniedException) -> {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(401);
response.getWriter().write(
JsonUtil.obj2Json(
Resps.error(RespsConsts.CODE_FAIL, new String[]{BizConsts.BASE_NOT_ROLE_MSG})
)
);
response.getWriter().close();
});
}
}

View File

@ -0,0 +1,281 @@
package com.example.demo.security.domain;
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 com.baomidou.mybatisplus.extension.activerecord.Model;
import com.yexuejc.base.util.JsonUtil;
import com.yexuejc.springboot.base.security.inte.User;
import java.io.Serializable;
import java.util.List;
/**
* <p>
* <p>
* </p>
*
* @author yexuejc
* @since 2018-05-27
*/
@TableName(resultMap = "BaseResultMap")
public class Consumer extends Model<Consumer> implements User {
private static final long serialVersionUID = 1L;
/**
* 用户id
*/
@TableId(value = "consumer_id", type = IdType.UUID)
private String consumerId;
/**
* 手机号
*/
@TableField("mobile")
private String mobile;
/**
* 密码md5
*/
@TableField("pwd")
private String pwd;
/**
* 账号是否启用
*/
@TableField("is_enable")
private boolean enable;
/**
* 账号是否没有过期
*/
@TableField("is_non_expire")
private boolean nonExpire;
/**
* 账号是否没有被锁定
*/
@TableField("is_non_lock")
private boolean nonLock;
/**
* 微信id
*/
@TableField("wechat_id")
private String wechatId;
/**
* qq id
*/
@TableField("qq_id")
private String qqId;
/**
* 微博id
*/
@TableField("weibo_id")
private String weiboId;
/**
* 昵称
*/
@TableField("nickname")
private String nickname;
/**
* 用户头像
*/
@TableField("head")
private String head;
/**
* 用户邮箱
*/
@TableField("email")
private String email;
/**
* 用户姓别 '男'
*/
@TableField("sex")
private String sex;
/**
* 角色权限
*/
@TableField(value = "roles", el = "roles,typeHandler=com.yexuejc.guansc.core.mybatis.handler.JsonTypeHandler")
private List<String> roles;
/**
* 支付密码
*/
@TableField("pay_pwd")
private String payPwd;
/**
* 注册方式
*/
@TableField("reg_type")
private String regType;
/**
* 第三方源头像路径
*/
@TableField("source_head")
private String sourceHead;
@Override
public String toString() {
return JsonUtil.obj2Json(this);
}
public String getConsumerId() {
return consumerId;
}
public Consumer setConsumerId(String consumerId) {
this.consumerId = consumerId;
return this;
}
public String getMobile() {
return mobile;
}
public Consumer setMobile(String mobile) {
this.mobile = mobile;
return this;
}
public String getPwd() {
return pwd;
}
@Override
public boolean getEnable() {
return this.enable;
}
@Override
public boolean getNonExpire() {
return this.nonExpire;
}
@Override
public boolean getNonLock() {
return this.nonLock;
}
public Consumer setPwd(String pwd) {
this.pwd = pwd;
return this;
}
public Consumer setEnable(boolean enable) {
this.enable = enable;
return this;
}
public Consumer setNonExpire(boolean nonExpire) {
this.nonExpire = nonExpire;
return this;
}
public Consumer setNonLock(boolean nonLock) {
this.nonLock = nonLock;
return this;
}
public String getWechatId() {
return wechatId;
}
public Consumer setWechatId(String wechatId) {
this.wechatId = wechatId;
return this;
}
public String getQqId() {
return qqId;
}
public Consumer setQqId(String qqId) {
this.qqId = qqId;
return this;
}
public String getWeiboId() {
return weiboId;
}
public Consumer setWeiboId(String weiboId) {
this.weiboId = weiboId;
return this;
}
public String getNickname() {
return nickname;
}
public Consumer setNickname(String nickname) {
this.nickname = nickname;
return this;
}
public String getHead() {
return head;
}
public Consumer setHead(String head) {
this.head = head;
return this;
}
public String getEmail() {
return email;
}
public Consumer setEmail(String email) {
this.email = email;
return this;
}
public String getSex() {
return sex;
}
public Consumer setSex(String sex) {
this.sex = sex;
return this;
}
public List<String> getRoles() {
return roles;
}
public Consumer setRoles(List<String> roles) {
this.roles = roles;
return this;
}
public String getPayPwd() {
return payPwd;
}
public Consumer setPayPwd(String payPwd) {
this.payPwd = payPwd;
return this;
}
public String getRegType() {
return regType;
}
public Consumer setRegType(String regType) {
this.regType = regType;
return this;
}
public String getSourceHead() {
return sourceHead;
}
public Consumer setSourceHead(String sourceHead) {
this.sourceHead = sourceHead;
return this;
}
@Override
protected Serializable pkVal() {
return this.consumerId;
}
}

View File

@ -0,0 +1,383 @@
package com.example.demo.security.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.demo.mapper.ConsumerMapper;
import com.example.demo.security.domain.Consumer;
import com.yexuejc.base.constant.RespsConsts;
import com.yexuejc.base.pojo.ApiVO;
import com.yexuejc.base.util.StrUtil;
import com.yexuejc.springboot.base.autoconfigure.MutiRedisAutoConfiguration;
import com.yexuejc.springboot.base.constant.BizConsts;
import com.yexuejc.springboot.base.constant.DictRegTypeConsts;
import com.yexuejc.springboot.base.constant.LogTypeConsts;
import com.yexuejc.springboot.base.exception.ThirdPartyAuthorizationException;
import com.yexuejc.springboot.base.security.ConsumerToken;
import com.yexuejc.springboot.base.security.ConsumerUser;
import com.yexuejc.springboot.base.security.inte.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* 数据库操作DB
*
* @author maxf
* @version 1.0
* @ClassName UserServiceImpl
* @Description
* @date 2018/11/8 17:31
*/
@Service("userserviceimpl")
public class UserServiceImpl implements UserService {
@Autowired
ConsumerMapper consumerMapper;
@Autowired
@Qualifier(MutiRedisAutoConfiguration.BEAN_REDIS_TEMPLATE1)
private RedisTemplate<Object, Object> redisTemplate;
/**
* 根据用户名到数据库查询用户
*
* @param username 登录账号
* @return
*/
@Override
public Object getConsumerByUserName(String username) {
if (StrUtil.isEmpty(username)) {
throw new UsernameNotFoundException("username为空一般是第三方登录来的直接抛出UsernameNotFoundException就是");
}
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("mobile", username);
Consumer consumer = consumerMapper.selectOne(queryWrapper);
if (null == consumer) {
/**
* 1.抛出UsernameNotFoundException这个异常如果是第三方登录会走 {@link #checkOpenId(ConsumerToken)}
* 2.抛出其他Exception可以自己到{@link MySecurityConfig#loginHodler(ConsumerAuthenticationProcessingFilter)}
* 里面的filter.setAuthenticationFailureHandler()中做特殊处理
*/
throw new UsernameNotFoundException("没有该账号相关信息");
}
//h2不支持json人为处理角色
ArrayList roles = new ArrayList<>();
roles.add("ROLE_CONSUMER");
consumer.setRoles(roles);
//1.consumer为User的实现类
// return consumer;
//2. 自己创建ConsumerUser直接返回
List<GrantedAuthority> authorities = new ArrayList<>();
for (String role : consumer.getRoles()) {
authorities.add(new SimpleGrantedAuthority(role));
}
ConsumerUser consumerUser = new ConsumerUser(consumer.getMobile(), consumer.getPwd(),
consumer.getEnable(), consumer.getNonExpire(), true, consumer.getNonLock(),
authorities, consumer.getConsumerId(), null, System.currentTimeMillis());
return consumerUser;
}
/**
* 到自己的reids里面校验短信验证码
*
* @param smsType {@linkplain BizConsts.CONSUMER_LOGIN_SMS} 业务id reids使用
* @param mobile 登录账号
* @param code 短信验证码
* @return
*/
@Override
public ApiVO checkSmsCode2Redis(String smsType, String mobile, String code) {
redisTemplate.afterPropertiesSet();
String rCode = (String) redisTemplate.opsForHash().get(smsType + "." + mobile, "code");
Integer validatedNums = (Integer) redisTemplate.opsForHash().get(smsType + "." + mobile, "validatedNums");
if (validatedNums == null) {
return new ApiVO(ApiVO.STATUS.F, RespsConsts.CODE_FAIL, "验证码过期,请重新获取");
} else if (validatedNums > 5) {
redisTemplate.delete(smsType + "." + mobile);
return new ApiVO(ApiVO.STATUS.F, RespsConsts.CODE_FAIL, "验证码过期,请重新获取");
}
if (code.equals(rCode)) {
redisTemplate.delete(smsType + "." + mobile);
return new ApiVO(ApiVO.STATUS.S);
} else {
validatedNums++;
redisTemplate.opsForHash().put(smsType + "." + mobile, "validatedNums", validatedNums);
return new ApiVO(ApiVO.STATUS.F, RespsConsts.CODE_FAIL, "验证码不正确");
}
}
/**
* 第三方登录
* 校验openid 根据自己业务做判断
*
* @param consumerToken 登录信息
* @return
*/
@Override
public Object checkOpenId(ConsumerToken consumerToken) {
ApiVO apiVO = new ApiVO(ApiVO.STATUS.F, "没有找到用户信息");
switch (consumerToken.getLogtype()) {
case LogTypeConsts.QQ:
apiVO = checkOpenid4QQ(consumerToken, true);
break;
case LogTypeConsts.WECHAT:
apiVO = checkOpenid4Wechat(consumerToken, true);
break;
case LogTypeConsts.WEIBO:
apiVO = checkOpenid4Weibo(consumerToken, true);
break;
default:
break;
}
if (apiVO.isFail()) {
/**
* 未查到:
* 1.返回null会走数据库没有这个openid[第三方账号]信息新增流程 {@link #addConsumer(ConsumerToken)}
* 2.也可以自己创建一个带有特殊标识的ConsumerUser然后在 {@link MySecurityConfig#loginHodler(ConsumerAuthenticationProcessingFilter)}
* 里面的filter.setAuthenticationSuccessHandler()中做特殊处理 ps:假装登录成功 :)
*/
return null;
}
//h2不支持json人为处理角色
ArrayList roles = new ArrayList<>();
roles.add("ROLE_CONSUMER");
apiVO.getObject1(Consumer.class).setRoles(roles);
//根据openid到数据库查到consumer返回
return apiVO.getObject1(Consumer.class);
}
/**
* {@link #checkOpenId(ConsumerToken)} 返回null会走该方法
* 没有账号时处理自己的业务此处必须返回 构造出的登录用户否则会抛出{@link ThirdPartyAuthorizationException 第三方授权异常}
* <br/>
*
* @param consumerToken 登录信息
* @return
*/
@Override
public Object addConsumer(ConsumerToken consumerToken) {
Consumer consumer = new Consumer();
consumer.setConsumerId(StrUtil.genUUID());
consumer.setMobile(StrUtil.isNotEmpty(consumerToken.getUsername()) ? consumerToken.getUsername() : consumerToken.getOpenid());
consumer.setPwd(StrUtil.toMD5("123456"));
consumer.setEnable(true);
consumer.setNonExpire(true);
consumer.setNonLock(true);
List<String> roles = new ArrayList<>();
roles.add("ROLE_CONSUMER");
consumer.setRoles(roles);
switch (consumerToken.getLogtype()) {
case LogTypeConsts.SMS:
ApiVO apiVO = checkSmsCode2Redis(BizConsts.CONSUMER_LOGIN_SMS, consumerToken.getUsername(),
consumerToken.getSmscode());
if (apiVO.isFail()) {
throw new ThirdPartyAuthorizationException("短信验证码错误");
}
consumer.setNickname(consumerToken.getUsername());
consumer.setHead("/head/def.png");
consumer.setRegType(DictRegTypeConsts.DICT_MOBILE);
break;
case LogTypeConsts.QQ:
consumer.setQqId(consumerToken.getOpenid());
consumer.setNickname(consumerToken.getNickname());
setHeader(consumerToken, consumer, false);
setSex(consumerToken, consumer);
consumer.setRegType(DictRegTypeConsts.DICT_QQ);
break;
case LogTypeConsts.WECHAT:
consumer.setWechatId(consumerToken.getOpenid());
consumer.setNickname(consumerToken.getNickname());
setHeader(consumerToken, consumer, false);
setSex(consumerToken, consumer);
consumer.setRegType(DictRegTypeConsts.DICT_WECHAT);
break;
case LogTypeConsts.WEIBO:
consumer.setWeiboId(consumerToken.getOpenid());
consumer.setNickname(consumerToken.getNickname());
setHeader(consumerToken, consumer, false);
setSex(consumerToken, consumer);
consumer.setRegType(DictRegTypeConsts.DICT_WEIBO);
break;
default:
throw new ThirdPartyAuthorizationException("暂不支持该第三方授权");
}
Integer result = consumerMapper.insert(consumer);
if (result < 1) {
/**
* 会抛出{@link ThirdPartyAuthorizationException 第三方授权异常}
*/
return null;
}
return consumer;
}
/**
* 第三方登录 QQ登录
*
* @param consumerToken 登录信息
* @param b
* @return
*/
public ApiVO checkOpenid4QQ(ConsumerToken consumerToken, boolean b) {
Consumer consumer = getConsumerByQQOpenid(consumerToken.getOpenid());
if (consumer == null) {
return new ApiVO(ApiVO.STATUS.F, "获取用户信息失败");
}
if (b && DictRegTypeConsts.DICT_QQ.equals(consumer.getRegType())) {
//如果是qq注册的登录的同时更新用户信息
updateConsumer(consumer, consumerToken);
}
return new ApiVO(ApiVO.STATUS.S).setObject1(consumer);
}
/**
* 第三方登录 微信登录
*
* @param consumerToken 登录信息
* @param b
* @return
*/
public ApiVO checkOpenid4Wechat(ConsumerToken consumerToken, boolean b) {
Consumer consumer = getConsumerByWechatOpenid(consumerToken.getOpenid());
if (consumer == null) {
return new ApiVO(ApiVO.STATUS.F, "获取用户信息失败");
}
if (b && DictRegTypeConsts.DICT_WECHAT.equals(consumer.getRegType())) {
//如果是微信注册的登录的同时更新用户信息
updateConsumer(consumer, consumerToken);
}
return new ApiVO(ApiVO.STATUS.S).setObject1(consumer);
}
/**
* 第三方登录 微博登录
*
* @param consumerToken 登录信息
* @param b
* @return
*/
public ApiVO checkOpenid4Weibo(ConsumerToken consumerToken, boolean b) {
Consumer consumer = getConsumerByWeiboOpenid(consumerToken.getOpenid());
if (consumer == null) {
return new ApiVO(ApiVO.STATUS.F, "获取用户信息失败");
}
if (b && DictRegTypeConsts.DICT_WEIBO.equals(consumer.getRegType())) {
//如果是微博注册的登录的同时更新用户信息
updateConsumer(consumer, consumerToken);
}
return new ApiVO(ApiVO.STATUS.S).setObject1(consumer);
}
public Consumer getConsumerByQQOpenid(String openid) {
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("qq_id", openid);
Consumer consumer = consumerMapper.selectOne(queryWrapper);
return consumer;
}
public Consumer getConsumerByWechatOpenid(String openid) {
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("wechat_id", openid);
Consumer consumer = consumerMapper.selectOne(queryWrapper);
return consumer;
}
public Consumer getConsumerByWeiboOpenid(String openid) {
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("weibo_id", openid);
Consumer consumer = consumerMapper.selectOne(queryWrapper);
return consumer;
}
/**
* 更新基本信息
*
* @param consumer
* @param consumerToken
*/
private void updateConsumer(Consumer consumer, ConsumerToken consumerToken) {
boolean b1, b2, b3;
b1 = b2 = b3 = true;
if (StrUtil.isNotEmpty(consumerToken.getNickname())) {
if (consumerToken.getNickname().equals(consumer.getNickname())) {
b1 = false;
}
consumer.setNickname(consumerToken.getNickname());
}
b2 = setHeader(consumerToken, consumer, true);
b3 = setSex(consumerToken, consumer);
if (!b1 && !b2 && !b3) {
return;
}
LambdaUpdateWrapper<Consumer> queryWrapper = new UpdateWrapper<>(new Consumer()).lambda();
try {
queryWrapper.set(Consumer::getNickname, consumer.getNickname())
.set(Consumer::getHead, consumer.getHead())
.set(Consumer::getSex, consumer.getSex())
.eq(Consumer::getConsumerId, consumer.getConsumerId());
consumerMapper.update(new Consumer(), queryWrapper);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 设置头像->上传网络图片到OSS
*
* @param consumerToken
* @param consumer
* @param isUpdate
*/
private boolean setHeader(ConsumerToken consumerToken, Consumer consumer, boolean isUpdate) {
if (StrUtil.isNotEmpty(consumerToken.getHead())) {
if (isUpdate) {
if (consumerToken.getHead().equals(consumer.getSourceHead())) {
//未改变头像
return false;
}
} else {
consumer.setSourceHead(consumerToken.getHead());
}
//应该上传至OSS后返回OSS地址
consumer.setHead(consumerToken.getHead());
// try {
// consumer.setHead(putOss4Head(null, consumerToken.getHead()));
// } catch (ImageException e) {
// return false;
// }
}
return true;
}
/**
* 设置性别
*
* @param consumerToken
* @param consumer
*/
private boolean setSex(ConsumerToken consumerToken, Consumer consumer) {
if (StrUtil.isNotEmpty(consumerToken.getSex())) {
if ("1".equals(consumerToken.getSex()) && !"".equals(consumer.getSex())) {
consumer.setSex("");
return true;
} else if ("2".equals(consumerToken.getSex()) && !"".equals(consumer.getSex())) {
consumer.setSex("");
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,83 @@
package com.example.demo.web;
import com.yexuejc.base.http.Resps;
import com.yexuejc.base.pojo.ApiVO;
import com.yexuejc.base.util.RegexUtil;
import com.yexuejc.base.util.StrUtil;
import com.yexuejc.springboot.base.autoconfigure.MutiRedisAutoConfiguration;
import com.yexuejc.springboot.base.constant.BizConsts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* <pre>
* Security 登录注册相关controller
* 主要实现
* 1.短信登录发送验证码
* 2.第三方登录绑定手机号以及绑定手机号发送验证码
* </pre>
*
* @author maxf
* @version 1.0
* @ClassName SecurityCtrl
* @Description
* @date 2018/11/9 10:52
*/
@RestController
public class SecurityCtrl {
@Autowired
@Qualifier(MutiRedisAutoConfiguration.BEAN_REDIS_TEMPLATE1)
RedisTemplate<Object, Object> redisTemplate;
/**
* 登录发送短信
*
* @param mobile
* @return
*/
@RequestMapping(value = "/login/{mobile}", method = RequestMethod.POST)
public Resps login(@PathVariable String mobile) {
if (!RegexUtil.regex(mobile, RegexUtil.REGEX_MOBILE)) {
return Resps.fail("手机号不正确");
}
ApiVO apiVO = sendSmsCode(BizConsts.CONSUMER_LOGIN_SMS, mobile);
if (apiVO.isFail()) {
return Resps.fail(apiVO.getMsg());
}
return Resps.success(apiVO.getMsg());
}
private ApiVO sendSmsCode(String smsType, String mobile) {
String smsId = StrUtil.genUUID(30);
String code = StrUtil.genNum().substring(2, 8);
//自己接入短信发送
boolean result = true;
if (result) {
//成功
//存reids
Map<String, Object> map = new HashMap<>();
map.put("smsId", smsId);
map.put("code", code);
map.put("trade_id", "短信返回id");
map.put("validatedNums", 0);
redisTemplate.afterPropertiesSet();
redisTemplate.opsForHash().putAll(smsType + "." + mobile, map);
// 过期时间5分钟
redisTemplate.expire(smsType + "." + mobile, 5 * 60, TimeUnit.SECONDS);
return new ApiVO(ApiVO.STATUS.S, "短信发送成功");
} else {
return new ApiVO(ApiVO.STATUS.F, "短信发送失败");
}
}
}

View File

@ -0,0 +1,65 @@
logging.level.root=info
#========================================================================================================================
#========================================================================================================================
#核心
#开启功能 redis webmvc
yexuejc.autoconfigure.redis.enable=true
#webmvc 包含以下功能
yexuejc.autoconfigure.webmvc.enable=true
#全局异常处理
yexuejc.ssl-ignore.enable=true
#开启HTTPSSSL请求证书验证忽略
yexuejc.global.exception.enable=true
#开启校验过滤器目前校验HTTP Header是否符合规范
yexuejc.web.validation-filter.enable=true
# 拦截类型请求路径0忽略模式默认拦截全部1拦截模式默认一个都不拦截
yexuejc.http.filter=0
#忽略路径示例放开swagger
yexuejc.http.filter.ignored=/,/swagger/**,/error,/v2/api-docs,/webjars/**
#========================================================================================================================
#========================================================================================================================
#========================================================================================================================
# security相关
#reids
#开启指定redis库db0默认开启
yexuejc.redis.db1=true
spring.redis.jedis.pool.max-active=100
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=3
spring.redis.host=121.42.165.89
spring.redis.password=
spring.redis.port=16379
#db
spring.h2.console.path=/h2-console
spring.h2.console.enabled=true
spring.h2.console.settings.web-allow-others=true
spring.datasource.username=sa
spring.datasource.password=123456
spring.datasource.url=jdbc:h2:mem:test;MODE=PostgreSQL
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.schema=classpath:db/schema.sql
spring.datasource.data=classpath:db/data.sql
#========================================================================================================================
#mybatis-plus
mybatis-plus.mapper-locations=classpath*:mapper/*.xml
#实体扫描多个package用逗号或者分号分隔
mybatis-plus.type-aliases-package=com.yexuejc.springboot.base.security.domain
#主键类型0:"数据库ID自增", 1:"用户输入ID",2:"该类型为未设置主键类型", 3:"全局唯一ID UUID",4:全局唯一ID (UUID),5:字符串全局唯一ID (idWorker 的字符串表示);
mybatis-plus.global-config.db-config.id-type=uuid
mybatis-plus.global-config.db-config.db-type=POSTGRE_SQL
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
mybatis-plus.global-config.db-config.field-strategy=not_empty
#驼峰下划线转换
mybatis-plus.global-config.db-config.column-underline=true
#逻辑删除配置下面3个配置
mybatis-plus.global-config.db-config.logic-delete-value=true
mybatis-plus.global-config.db-config.logic-not-delete-value=false
#配置返回数据库(column下划线命名&&返回java实体是驼峰命名)自动匹配无需as没开启这个SQL需要写as select user_id as userId
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.cache-enabled=false
#========================================================================================================================

View File

@ -0,0 +1,34 @@
INSERT INTO consumer (consumer_id,
mobile,
pwd,
is_enable,
is_non_expire,
is_non_lock,
wechat_id,
qq_id,
weibo_id,
nickname,
head,
email,
sex,
roles,
pay_pwd,
reg_type,
source_head)
VALUES ('119d8c62b8b04154a073b3f6c3d9e14f',
'18202837563',
'e10adc3949ba59abbe56e057f20f883e',
't',
't',
't',
'ogIXq0HrDq3kS6MAHqMI1RUqBrGw',
NULL,
NULL,
'18202837563',
'head/6dc93e2e0809426ca8a9e6ede30b0b50.JPEG',
NULL,
'',
'[ROLE_CONSUMER, ROLE_LAYER]',
NULL,
'S',
'https://wx.qlogo.cn/mmopen/vi_32/MftzC3yHluDbjZ9c3sYEibUuXNkC3pha8E6pibZO3Wh0Zop0bqHLcltjmrENc4R8Xm6oJECQGibAxZot1v9PR1hsw/132');

View File

@ -0,0 +1,42 @@
CREATE TABLE consumer (
consumer_id varchar(32) NOT NULL DEFAULT NULL::character varying,
mobile varchar(50) NOT NULL DEFAULT NULL::character varying,
pwd varchar(32) DEFAULT NULL::character varying,
is_enable bool DEFAULT true,
is_non_expire bool DEFAULT true,
is_non_lock bool DEFAULT true,
wechat_id varchar(50) DEFAULT NULL::character varying,
qq_id varchar(50) DEFAULT NULL::character varying,
weibo_id varchar(50) DEFAULT NULL::character varying,
nickname varchar(50) DEFAULT NULL::character varying,
head varchar(255) DEFAULT NULL::character varying,
email varchar(32) DEFAULT NULL::character varying,
sex varchar(1) DEFAULT NULL::character varying,
roles varchar(255),
pay_pwd varchar(32) DEFAULT NULL::character varying,
reg_type varchar(10) ,
source_head varchar(255)
)
;
COMMENT ON COLUMN consumer.consumer_id IS '用户id';
COMMENT ON COLUMN consumer.mobile IS '手机号';
COMMENT ON COLUMN consumer.pwd IS '密码md5';
COMMENT ON COLUMN consumer.is_enable IS '账号是否启用';
COMMENT ON COLUMN consumer.is_non_expire IS '账号是否没有过期';
COMMENT ON COLUMN consumer.is_non_lock IS '账号是否没有被锁定';
COMMENT ON COLUMN consumer.wechat_id IS '微信id';
COMMENT ON COLUMN consumer.qq_id IS 'qq id';
COMMENT ON COLUMN consumer.weibo_id IS '微博id';
COMMENT ON COLUMN consumer.nickname IS '昵称';
COMMENT ON COLUMN consumer.head IS '用户头像';
COMMENT ON COLUMN consumer.email IS '用户邮箱';
COMMENT ON COLUMN consumer.sex IS '用户姓别 '''',‘女’';
COMMENT ON COLUMN consumer.roles IS '角色、权限';
COMMENT ON COLUMN consumer.pay_pwd IS '支付密码';
COMMENT ON COLUMN consumer.reg_type IS '注册方式';
COMMENT ON COLUMN consumer.source_head IS '第三方源头像路径';
-- ----------------------------
-- Primary Key structure for table consumer
-- ----------------------------
ALTER TABLE consumer ADD CONSTRAINT consumer_pkey PRIMARY KEY (consumer_id);

View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.ConsumerMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.example.demo.security.domain.Consumer">
<id column="consumer_id" property="consumerId"/>
<result column="mobile" property="mobile"/>
<result column="pwd" property="pwd"/>
<result column="is_enable" property="enable"/>
<result column="is_non_expire" property="nonExpire"/>
<result column="is_non_lock" property="nonLock"/>
<result column="wechat_id" property="wechatId"/>
<result column="qq_id" property="qqId"/>
<result column="weibo_id" property="weiboId"/>
<result column="nickname" property="nickname"/>
<result column="head" property="head"/>
<result column="email" property="email"/>
<result column="sex" property="sex"/>
<result column="roles" property="roles"
typeHandler="com.example.demo.mapper.handler.JsonTypeHandler"/>
<result column="pay_pwd" property="payPwd"/>
<result column="reg_type" property="regType"/>
<result column="source_head" property="sourceHead"/>
</resultMap>
<insert id="insert">
INSERT INTO consumer (consumer_id,
mobile,
pwd,
is_enable,
is_non_expire,
is_non_lock,
wechat_id,
qq_id,
weibo_id,
nickname,
head,
email,
sex,
roles,
pay_pwd,
reg_type,
source_head)
VALUES (#{consumerId},
#{mobile},
#{pwd},
#{enable},
#{nonExpire},
#{nonLock},
#{wechatId},
#{qqId},
#{weiboId},
#{nickname},
#{head},
#{email},
#{sex},
#{roles,typeHandler=com.example.demo.mapper.handler.JsonTypeHandler},
#{payPwd},
#{regType},
#{sourceHead});
</insert>
<select id="selectOne" resultMap="BaseResultMap">
select * from consumer
<where>${ew.sqlSegment}</where>
</select>
<update id="updateRoles">
update consumer
<set>
<if test='et.roles!=null'>
roles = #{et.roles,typeHandler=com.example.demo.mapper.handler.JsonTypeHandler},
</if>
mdfy_time=now(),
mdfy_by=#{et.mdfyBy}
</set>
where
consumer_id=#{et.consumerId}
</update>
</mapper>

View File

@ -0,0 +1,16 @@
package com.example.demo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Test
public void contextLoads() {
}
}

View File

@ -0,0 +1,31 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
### VS Code ###
.vscode/

View File

@ -0,0 +1,63 @@
# yexuejc-springboot-simple
### 说明
>本工程是yexuejc-springboot的使用示例新接入请参考本工程
#### 什么都不用
<details>
<summary>直接新建一个springboot工程 pom.xml 配置</summary>
```
<?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>
<parent>
<groupId>com.yexuejc.springboot</groupId>
<artifactId>yexuejc-springboot-parent</artifactId>
<version>1.2.1</version>
</parent>
<groupId>top.yexuejc</groupId>
<artifactId>yexuejc-springboot-simple</artifactId>
<version>0.0.1</version>
<name>yexuejc-springboot-simple</name>
<description>测试工程</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.yexuejc.springboot</groupId>
<artifactId>yexuejc-springboot-base</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
```
</details>
#### 使用多端登录
参考[使用多端登录](../springboot-security-login-simple/README.md)

View File

@ -0,0 +1,286 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
wget "$jarUrl" -O "$wrapperJarPath"
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
curl -o "$wrapperJarPath" "$jarUrl"
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

View File

@ -0,0 +1,161 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
echo Found %WRAPPER_JAR%
) else (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
echo Finished downloading %WRAPPER_JAR%
)
@REM End of extension
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%

View File

@ -0,0 +1,47 @@
<?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>
<parent>
<groupId>com.yexuejc.springboot</groupId>
<artifactId>yexuejc-springboot-parent</artifactId>
<version>2.1.0</version>
</parent>
<groupId>top.yexuejc</groupId>
<artifactId>yexuejc-springboot-simple</artifactId>
<version>0.0.1</version>
<name>yexuejc-springboot-simple</name>
<description>测试工程</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.yexuejc.springboot</groupId>
<artifactId>yexuejc-springboot-base</artifactId>
<version>${parent.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,14 @@
package top.yexuejc.springboot.simple;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class YexuejcSpringbootSimpleApplication {
public static void main(String[] args) {
SpringApplication.run(YexuejcSpringbootSimpleApplication.class, args);
}
}

View File

@ -0,0 +1,2 @@
logging.level.root=info

View File

@ -0,0 +1,16 @@
package top.yexuejc.springboot.simple;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class YexuejcSpringbootSimpleApplicationTests {
@Test
public void contextLoads() {
}
}