# springcloud-alibaba-learn
**Repository Path**: study-base/springcloud-alibaba-learn
## Basic Information
- **Project Name**: springcloud-alibaba-learn
- **Description**: spring cloud alibaba 学习
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-06-12
- **Last Updated**: 2022-08-08
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# nacos 命名空间及GROUP使用规范
nacos namespace 可以用作区分不同环境
nacos group 可以作为业务组区分
# nacos config配置创建
config/learn-common.yaml为公共配置,需要放到Nacos Config,DataId为learn-common.yaml
config/learn-xxx.yaml为各个项目的配置,同样需要放到Nacos Config,DataId为learn.xxx.yaml
# 不同环境部署时需要设置的环境变量
spring.cloud.nacos.discovery.server-addr=http://10.1.80.62:8848
spring.cloud.nacos.discovery.namespace=test
spring.cloud.nacos.discovery.group=XXX_GROUP
spring.cloud.nacos.config.namespace=test
spring.cloud.nacos.config.group=XXX_GROUP
# 若要实时更新配置值
动态刷新配置的注解@RefreshScope
# 解决网关转发到服务报 Service Unavailable错误
https://blog.csdn.net/qq_36525300/article/details/120224966
Nacos 自带 spring-cloud-starter-netflix-ribbon,而 Netflix 的 Ribbon 已进入维护阶段,从最新的 SpringCloud 2020 版本开始就需要改用 Spring cloud loadbalancer
# gateway 本例中
访问http://127.0.0.1:9999/learn-admin/echo/demo_name 网关即会将请求转发到服务ID为learn-admin的服务,本例是http://127.0.0.1:8802/echo/demo_name,转发前去掉learn-admin前缀
# 如果要使用openfeign调用那么需要引入以下依赖
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.cloud
spring-cloud-starter-loadbalancer
# token生成配置
项目使用JWT实现access_token,关于access_token生成步骤的配置如下:
> 生成密钥库
使用JDK工具的keytool生成JKS密钥库(Java Key Store),并将meeleet.jks放到resources目录
keytool -genkey -alias jwt -keyalg RSA -keypass 123456 -keystore meeleet.jks -storepass 123456
> 获取公钥
keytool -list -rfc --keystore meeleet.jks | openssl x509 -inform pem -pubkey
# 单元测试
## 单元测试不适用nacos config,而是使用本地配置
## 单元测试使用h2
mysql2h2-converter-tool-0.2.2.jar 可以将mysql的SQL转为H2支持的SQL
# Postman调试
请求头
Authorization => Basic Y2xpZW50OjEyMzQ1Ng==
Y2xpZW50OjEyMzQ1Ng== 是 client_id:client_secret的base64编码结果
# OpenAPI3 聚合层服务增加如下OpenAPI3的配置类,以方便使用OAuth2认证后保持Token
```java
/**
* OpenAPI 配置
*
* @Author jaychang
* @Version 1.0.0
*/
@SecurityScheme(name = "securityAuth", type = SecuritySchemeType.OAUTH2,
flows = @OAuthFlows(
password = @OAuthFlow(
tokenUrl = "${springdoc.oAuthFlow.tokenUrl}",
scopes = {@OAuthScope(name = "all", description = "all scope")})
))
@Configuration
public class OpenAPI30Configuration implements WebMvcConfigurer {
@Bean
public OpenAPI customizeOpenAPI() {
OpenAPI openAPI = new OpenAPI();
openAPI.info(new Info().title("Auth API")
.description("Spring shop sample application")
.version("v1.0.0")
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("SpringShop Wiki Documentation")
.url("https://springshop.wiki.github.org/docs"));
return openAPI;
}
}
```
```java
# 如果仅仅是JWT Token,并没有用到OAuth2可以用以下代码
// 声明全局保持Token
// final String securitySchemeName = "bearerAuth";
// openAPI.addSecurityItem(new SecurityRequirement()
// .addList(securitySchemeName))
// .components(new Components()
// .addSecuritySchemes(securitySchemeName, new io.swagger.v3.oas.models.security.SecurityScheme()
// .name(securitySchemeName)
// .type(io.swagger.v3.oas.models.security.SecurityScheme.Type.HTTP)
// .scheme("bearer")
// .bearerFormat("JWT")));
```
# 网关访问api文档方式
http://localhost:9999/swagger-ui.html
# 微服务直接访问api文档
http://localhost:9999/learn-ops/swagger-ui.html
http://localhost:9999/learn-ops/swagger-ui/index.html
以上两种方式都可以
# nacos配置复制的问题
learn-auth复制到nacos config,会变成learn_auth,需要特别注意
# 认证相关问题
## 验证码登录为什么不需要提供Provider
那是因为验证码登录Authentication的类型,与用户名密码登录的Authentication的类型是一样的,都是UsernamePasswordAuthenticationToken,
org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.supports
```
@Override
public boolean supports(Class> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
```
故可以复用DaoAuthenticationProvider,无需自己定义一个Provider
## 不同用户体系的认证方法
举例:当app端、运营端、web端都需要grant_type=password的登录模式时,由于app端、web端与运营端是不同的用户体系,需要使用不同的UserDetailService
方法1: 定义不同的grant_type
app端、web端定义grant_type = member_password
运营端定义grant_type = operator_password
定义多个Grant,再定义多个Provider
方法2: grant_type都一样,grant_type = password
参考com.meeleet.learn.auth.security.extension.refresh.PreAuthenticatedUserDetailsService
根据不同client_id对应不同UserDetailService,定义一个UserDetailService代理类,代理不同client_id的UserDetailService
姑且就叫这个UserDetailService代理为MultipleUserDetailService
问题是client_id哪里可以得到呢?
看了OAuth2密码模式的认证流程,我们可以得知,需要自定义TokenGranter(在ResourceOwnerPasswordTokenGranter基础上增加client_id的信息)、因此也需要自定义AuthenticationToken(可继承UsernamePasswordAuthenticationToken,增加client_id信息)
,还需要自定义AuthenticationProvider(可继承DaoAuthenticationProvider,重写retrieveUser方法)
## 如果报以下错误
```
{
"code": "B0001",
"data": null,
"msg": "Unauthorized grant type: captcha"
}
```
则相应的client_id要配置相应的authorized_grant_types,若开发时觉得不便,可以去掉缓存注解
# 自定义/oauth/token 返回格式
默认返回格式不是我们需要{"code":xxx,"data":{...},"msg":"zzz"}
## 方法一
自己写个Controller,定义一个/oauth/token方法,然后引入TokenEndpoint,方法内部直接调用它的postAccessToken方法
但是这样的话,TokenEndpoint内部定义的很多异常处理方法就失效了。无法通过自定义WebResponseExceptionTranslator来处理异常
不过也没什么关系,我们自己可以定义一个异常处理类(通过@RestControllerAdvice注解来实现),来依样画葫芦处理各种异常
## 方法二
自定义WebResponseExceptionTranslator来处理异常
# Minio 与OkHttp 版本冲突问题
minio版本降低到8.2.2