代码地址与接口看总目录:【学习笔记】记录冷冷-pig项目的学习过程,大概包括Authorization Server、springcloud、Mybatis Plus~~~_清晨敲代码的博客-CSDN博客
之前只零碎的学习过spring-cloud-alibaba,并没有全面了解过,这次学习pig框架时,想着可以根据这个项目学习一下,练练手,于是断断续续的用了几天时间搭建了一下基础框架。目前就先重点记录一下遇到的问题吧,毕竟流程也不是特别复杂,就是有的东西没遇到过了解的也不深~
上篇文章:No6.从零搭建spring-cloud-alibaba微服务框架,实现fegin、gateway、springevent等(一)_清晨敲代码的博客-CSDN博客
上篇文章包括:
1.将服务系统注册到nacos注册中心;
2.通过nacos实现配置动态更新;
3.添加fegin服务,实现服务之间调用;
4.添加网关(学会使用webflux,学会添加过滤器);
5.添加log服务,通过springevent实现,并使用注解使用(使用AOP);
本篇文章包括:
6.添加 mysql 数据库调用,并使用mybatis-plus操作;
7.在认证模块添加用户认证,基于oauth2的自定义密码模式(已认证用户是基于自定义token加redis持久化,不是session);
剩余包括(会有变动):
8.在upms资源模块添加对accesstoken校验逻辑,使用spring-security-oauth2-resource-server的BearerTokenAuthenticationFilter逻辑加上自定义校验token逻辑;
9.添加用户权限校验等逻辑,需要考虑微服务内部调用不鉴权逻辑;
目录
A6.添加 mysql 数据库调用,并使用mybatis-plus操作;
A7.添加用户认证,基于oauth2的自定义密码模式(已认证用户是基于自定义token加redis持久化,不是session);
添加pig-common-mybatis模块,主要处理mybatis-plus的配置,不配置这个也是可以的。
具体的mysql数据库调用在pig-upms-biz模块。
先来看基本的使用步骤
1.导包
2.添加数据库实体类;
3.添加mapper接口,可以继承mps提供的BaseMapper,也可以添加自定义mapper.xml;并让其被扫描到
4.添加service类,自定义后可以继承mps提供的IService和ServiceImpl;并添加到容器中
5.在controller中使用;
6.在application.xml中配置mapper-locations来扫描Mapper接口对应的XML文件,和其他mps配置信息;
-
- <dependency>
- <groupId>com.baomidougroupId>
- <artifactId>mybatis-plus-boot-starterartifactId>
- dependency>
-
- <dependency>
- <groupId>mysqlgroupId>
- <artifactId>mysql-connector-javaartifactId>
- dependency>
- //2.基础实体类,类似于创建时间等内容
- @Getter
- @Setter
- public class BaseEntity implements Serializable {
- /**
- * 创建者
- */
- @TableField(fill = FieldFill.INSERT)
- private String createBy;
-
- /**
- * 创建时间
- */
- @TableField(fill = FieldFill.INSERT)
- private LocalDateTime createTime;
-
- /**
- * 更新者
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private String updateBy;
-
- /**
- * 更新时间
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private LocalDateTime updateTime;
- }
-
-
-
-
-
- @Data
- @EqualsAndHashCode(callSuper = true)
- public class SysUser extends BaseEntity {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 主键ID
- */
- @TableId(value = "user_id", type = IdType.AUTO)
- private Long userId;
-
- /**
- * 用户名
- */
- private String username;
-
- 。。。
-
- /**
- * 0-正常,1-删除
- */
- @TableLogic(value = "0", delval = "4")
- private String delFlag;
-
- }
- //3.继承mps提供的 BaseMapper ,就可以使用他默认提供的方法。同时也可以添加 mapper.xml ,使用自定义的方法
- //要么添加 @Mapper,要么添加@Mapperscan
-
- @Mapper
- public interface SysUserMapper extends BaseMapper
{ -
- /**
- * @Description: 通过ID查询用户信息
- * @param id
- * @Return: com.pig4cloud.pig.admin.api.vo.UserVO
- */
- UserVO getUserVoById(Long id);
-
- /**
- * @Description: 分页查询用户信息(含角色)
- * @param page
- * @param userDTO
- * @Return: com.baomidou.mybatisplus.core.metadata.IPage
- */
- IPage
getUserVosPage(Page page, @Param("query") UserDTO userDTO); -
-
- }
- //4.添加service类,自定义后可以继承mps提供的IService和ServiceImpl;并添加到容器中
- //接口类和impl实现类都需要实现mps提供的类,然后就可以使用mps的service提供的方法
-
- public interface SysUserService extends IService
{ -
- /**
- * @Description: 新增/保存用户信息
- * @param userDto
- * @Return: java.lang.Boolean
- */
- Boolean saveUser(UserDTO userDto);
-
-
- }
-
-
- @Slf4j
- @Service
- @RequiredArgsConstructor
- public class SysUserServiceImpl extends ServiceImpl
implements SysUserService { -
- private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
-
- /**
- * @Description: 新增/保存用户信息
- * @param userDto
- * @Return: java.lang.Boolean
- */
- @Override
- public Boolean saveUser(UserDTO userDto) {
-
- SysUser sysUser = new SysUser();
- BeanUtils.copyProperties(userDto, sysUser);
- sysUser.setDelFlag(CommonConstants.STATUS_NORMAL);
- sysUser.setPassword(ENCODER.encode(userDto.getPassword()));
-
- //this.save(sysUser); 这俩有舍区别? service.save() 内部调用的也是 basesmapper.insert()
- baseMapper.insert(sysUser);
-
- //这里可以处理用户其他关联信息
-
-
- return Boolean.TRUE;
- }
-
- }
- //5.在controller中使用;
-
- @RestController
- @RequiredArgsConstructor
- @RequestMapping("/user")
- public class UserController {
-
- private final SysUserService userService;
-
-
- /**
- * @Description: 添加用户
- * @param userDto
- * @Return: com.pig4cloud.pig.common.core.util.R
- */
- @SysLog("添加用户")
- @PostMapping
- public R
user(@RequestBody UserDTO userDto) { -
- SysUser sysUser = userService.getOne(Wrappers.
lambdaQuery().eq(SysUser::getUsername,userDto.getUsername())); - if(sysUser != null){
- return R.failed("用户名已存在");
- }
-
- sysUser = userService.getOne(Wrappers.
lambdaQuery().eq(SysUser::getPhone,userDto.getPhone())); - if(sysUser != null){
- return R.failed("手机号码已存在");
- }
-
- return R.ok(userService.saveUser(userDto));
- }
-
- }
- # 6.application.yml 或者 nacos 里面的配置文件里面,配置mybatis扫描mapper.xml文件
-
- mybatis-plus:
- # 默认和mapper接口所在的包名相同
- mapper-locations: classpath:/mapper/*Mapper.xml
- global-config:
- banner: false
- db-config:
- # 主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
- id-type: auto
- # 表名是否使用驼峰转下划线命名,只对表名生效。
- table-underline: true
- # 逻辑已删除值,(逻辑删除下有效)。
- logic-delete-value: 1
- # 逻辑未删除值,(逻辑删除下有效)。
- logic-not-delete-value: 0
- configuration:
- # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
- map-underscore-to-camel-case: true
最后使用 apifox 进行测试,完美实现。
这里需要记住 mybatis-plus 里面的注解,例如 @TableId(value = "user_id", type = IdType.AUTO) @TableLogic(value = "0", delval = "4") @TableField(fill = FieldFill.INSERT) 等~还有配置文件里面的,需要详细的记住~
还有就是原理需要搞明白。
使用oauth2的方式实现密码模式的用户授权认证,暂时只校验是否身份认证,不进行权限设置。
就是相当于用户通过密码模式获取到token ,测试时只需要测试这个接口即可。
主要步骤有:
1.导入oauth2依赖的包;
2.在pig-common-secuity中添加获取用户信息的UserDetailsService自定义类,同时需要添加UserDetails的实现类;然后在pig-upms-biz中添加fegin接口,以及其相关的mybatis业务类;将需要到的service类添加到 META-INF/string.factories 中,以便添加到容器中;
3.在pig-auth中添加用户身份认证provider(类似于DaoAuthenticationProvider),能够调用UserDetailsService,最终并返回已认证的Authentication;会使用到2.
4.在pig-common-secuity中添加自定义的oauth2认证管理OAuth2AuthorizationService,他的主要作用是记录已认证的用户信息及使用的客户端信息,通过redis持久化;【放这个模块是为了资源端也能共用】,将service类添加到 META-INF/string.factories 中,以便添加到容器中;
5.在pig-common-secuity中添加自定义的注册客户端的持久化管理 RegisteredClientRepository ,他的主要作用就是从数据库中获取已注册的客户端信息RegisteredClient;具体的增删改在pig-upms-biz业务中,这里只需要查询即可;将service类添加到 META-INF/string.factories 中,以便添加到容器中;
6.在pig-auth中添加自定义OAuth2TokenGenerator生成器,若需要增强可以自定义OAuth2TokenCustomizer类;
7.在pig-auth中添加oauth2资源端用户认证过程中需要的converter、provider、token,其中会使用到3.4.5.中的类;
8.在pig-auth中添加自定义的AuthenticationFailureHandler、AuthenticationSuccessHandler的认证失败成功处理器;
9.在pig-auth中添加认证服务器配置;
- <dependency>
- <groupId>org.springframework.securitygroupId>
- <artifactId>spring-security-oauth2-authorization-serverartifactId>
- <version>${spring.authorization.version}version>
- dependency>
- //2.pig-common-secuity
-
- com.pig4cloud.pig.common.security.service.PigUser extends User implements OAuth2AuthenticatedPrincipal
- com.pig4cloud.pig.common.security.service.PigUserDetailsService extends UserDetailsService, Ordered
- com.pig4cloud.pig.common.security.service.PigUserDetailsServiceImpl implements PigUserDetailsService
-
- //然后将这个实现类添加到 /resources/META-INF/spring.factories 里面,就能自动注入到使用的启动模块中
-
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.pig4cloud.pig.common.security.service.PigUserDetailsServiceImpl
-
-
- //--------------
-
- //在 pig-upms-api 里面添加 openfegin 接口,也可以直接加到消费端 auth 里面;
- //这个接口直接就用用户模块里面的 获取用户全部信息(包括权限) = /user/info/{username}
-
- @FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.UMPS_SERVICE)
- com.pig4cloud.pig.admin.api.feign.auth.RemoteUserService
-
-
- //3.在 pig-auth 模块里面添加 provider,这个接口直接继承 AbstractUserDetailsAuthenticationProvider ,只需要重写获取用户信息方法、校验密码方法
-
- com.pig4cloud.pig.auth.support.core.PigDaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider{
- 会用到 PigUserDetailsServiceImpl 类型对象
- }
- //4.在pig-common-secuity中
-
- com.pig4cloud.pig.common.security.service.PigRedisOAuth2AuthorizationService implements OAuth2AuthorizationService{
- 里面会用到 redis ,会将产生的 accesstoken、refreshtoken、code、state等信息存到 redis里面
- private final RedisTemplate
redisTemplate; - }
-
- //然后将这个实现类添加到 /resources/META-INF/spring.factories 里面,就能自动注入到使用的启动模块中
-
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.pig4cloud.pig.common.security.service.PigUserDetailsServiceImpl,\
- com.pig4cloud.pig.common.security.service.PigRedisOAuth2AuthorizationService,\
- com.pig4cloud.pig.common.security.service.PigRemoteRegisteredClientRepository
-
-
- //--------------
-
- //用到了 redis 就得添加 RedisTemplate 到容器中,在 pig-common-core 中添加 redis 配置
-
- com.pig4cloud.pig.common.core.config.RedisTemplateConfiguration{}
-
- //然后将这个 configuration 添加到 /resources/META-INF/spring.factories 里面,就能自动注入到使用的启动模块中
-
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.pig4cloud.pig.common.core.config.JacksonConfiguration,\
- com.pig4cloud.pig.common.core.util.SpringContextHolder,\
- com.pig4cloud.pig.common.core.config.RedisTemplateConfiguration
- //5.在pig-common-secuity中
-
- com.pig4cloud.pig.common.security.service.PigRemoteRegisteredClientRepository implements RegisteredClientRepository{
- //从 upms 模块里面调用持久的客户端信息
- private final RemoteClientDetailsService clientDetailsService;
- }
-
- //然后将这个实现类添加到 /resources/META-INF/spring.factories 里面,就能自动注入到使用的启动模块中
-
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.pig4cloud.pig.common.security.service.PigUserDetailsServiceImpl,\
- com.pig4cloud.pig.common.security.service.PigRedisOAuth2AuthorizationService,\
- com.pig4cloud.pig.common.security.service.PigRemoteRegisteredClientRepository
-
-
- //--------------
-
- //在 pig-upms-api 里面添加 openfegin 接口,也可以直接加到消费端 auth 里面;
- //这个接口直接就用用户模块里面的 获取某个客户端信息 = /client/getClientDetailsById/{clientId}
-
- @FeignClient(contextId = "remoteClientDetailsService", value = ServiceNameConstants.UMPS_SERVICE)
- com.pig4cloud.pig.admin.api.feign.auth.RemoteClientDetailsService
- //6. pig-auth
-
- com.pig4cloud.pig.auth.support.core.CustomeOAuth2AccessTokenGenerator implements OAuth2TokenGenerator
- com.pig4cloud.pig.auth.support.core.CustomeOAuth2AccessTokenGenerator.OAuth2AccessTokenClaims extends OAuth2AccessToken implements ClaimAccessor
- com.pig4cloud.pig.auth.support.core.CustomeOAuth2TokenCustomizer implements OAuth2TokenCustomizer
- //7.pig-auth
-
- //基类
- com.pig4cloud.pig.auth.support.base.OAuth2ResourceOwnerBaseAuthenticationToken extends AbstractAuthenticationToken{
- private final AuthorizationGrantType authorizationGrantType;
- //这里的是客户端认证信息
- private final Authentication clientPrincipal;
- private final Set
scopes; - private final Map
additionalParameters; - }
- com.pig4cloud.pig.auth.support.base.OAuth2ResourceOwnerBaseAuthenticationConverter< T extends OAuth2ResourceOwnerBaseAuthenticationToken> implements AuthenticationConverter
- com.pig4cloud.pig.auth.support.base.OAuth2ResourceOwnerBaseAuthenticationProvider
extends OAuth2ResourceOwnerBaseAuthenticationToken> implements AuthenticationProvider{ - private final AuthenticationManager authenticationManager;
- private final OAuth2AuthorizationService oAuth2AuthorizationService;
- private final OAuth2TokenGenerator extends OAuth2Token> oAuth2TokenGenerator;
- }
-
- //实现类
- com.pig4cloud.pig.auth.support.password.OAuth2ResourceOwnerPasswordAuthenticationToken extends OAuth2ResourceOwnerBaseAuthenticationToken
- com.pig4cloud.pig.auth.support.password.OAuth2ResourceOwnerPasswordAuthenticationConverter extends OAuth2ResourceOwnerBaseAuthenticationConverter
- com.pig4cloud.pig.auth.support.password.OAuth2ResourceOwnerPasswordAuthenticationProvider extends OAuth2ResourceOwnerBaseAuthenticationProvider
-
- //8. pig-auth
-
- com.pig4cloud.pig.auth.support.handler.PigAuthenticationSuccessEventHandler implements AuthenticationSuccessHandler
- com.pig4cloud.pig.auth.support.handler.PigAuthenticationFailureEventHandler implements AuthenticationFailureHandler
- //9. pig-auth 专门配置 oauth2认证的安全配置
-
- @EnableWebSecurity(debug = true) //这个注解会触发创建 HttpSecurity bean ~
- @RequiredArgsConstructor
- com.pig4cloud.pig.auth.config.AuthorizationServerConfiguration{
-
- private final OAuth2AuthorizationService authorizationService;
-
- private final RegisteredClientRepository registeredClientRepository;
-
- @Bean
- @Order(Ordered.HIGHEST_PRECEDENCE)
- SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-
- OAuth2AuthorizationServerConfigurer
authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer<>(); -
- //配置个性化客户端认证(根据请求参数判断是否可以客户端认证)
- http.apply(authorizationServerConfigurer.clientAuthentication((oAuth2ClientAuthenticationConfigurer) -> {
- //配置授权失败的处理器
- oAuth2ClientAuthenticationConfigurer.errorResponseHandler(new PigAuthenticationFailureEventHandler()); // 个性化客户端认证
- }));
-
- //配置个性化认证授权端点(获取 accestokende 的端点)
- http.apply(authorizationServerConfigurer.tokenEndpoint(oAuth2TokenEndpointConfigurer -> {
- oAuth2TokenEndpointConfigurer.accessTokenRequestConverter(accessTokenRequestConverter()) // 注入自定义的授权认证 Converter 转化器
- .accessTokenResponseHandler(new PigAuthenticationSuccessEventHandler()) //配置认证失败的处理器
- .errorResponseHandler(new PigAuthenticationFailureEventHandler());//配置认证成功的处理器
-
- }));
-
- //配置端点元数据统一发行路径,其中各个端点路径都有默认使用值(也可以自定义配置,例如使用.authorizationEndpoint()配置授权请求端点)
- http.apply(authorizationServerConfigurer.providerSettings(ProviderSettings.builder().issuer(SecurityConstants.PROJECT_LICENSE).build()));
-
- //配置自定义授权信息token持久化到redis的管理类(会放到http的share)
- http.apply(authorizationServerConfigurer.authorizationService(authorizationService));
-
- //配置已注册的客户端信息的管理类(会放到http的share)
- http.apply(authorizationServerConfigurer.registeredClientRepository(registeredClientRepository));
-
-
- //拿到aotuh2需要的endpoint端点
- RequestMatcher endpoint = authorizationServerConfigurer.getEndpointsMatcher();
-
- SecurityFilterChain securityFilterChain = http
- //配置过滤链拦截的端点(过滤链默认是任意端点,可以通过这个设置,只有匹配中这写端点,才会进入这个过滤链)
- .requestMatcher(endpoint)
- //配置端点的权限(默认提供的oauth2的端点是需要认证权限的,例如/oauth2/introspect)
- .authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated())
- // .formLogin()
- // .and()
- .csrf().disable()
- //build SecurityFilterChain
- .build();
-
- //注入所有自定义认证授权需要的 provider 对象
- addCustomOAuth2GrantAuthenticationProvider(http);
-
- return securityFilterChain;
- }
-
- /**
- * @Description: request -> xToken 注入请求转换器
- * 1、授权码模式(暂无)
- * 2、隐藏式(暂无)
- * 3、密码式(自定义的)
- * 4、客户端凭证(暂无)
- * @param
- * @Return: org.springframework.security.web.authentication.AuthenticationConverter
- */
- public AuthenticationConverter accessTokenRequestConverter(){
- //new一个token转换器委托器,其中包含自定义密码模式认证转换器和刷新令牌认证转换器
- return new DelegatingAuthenticationConverter(Arrays.asList(
- new OAuth2ResourceOwnerPasswordAuthenticationConverter(),
- // 访问令牌请求用于OAuth 2.0刷新令牌授权 ——刷新token
- new OAuth2RefreshTokenAuthenticationConverter()
- //有需要到就要添加上
- // // 访问令牌请求用于OAuth 2.0授权码授权 ——授权码模式获取token
- // new OAuth2AuthorizationCodeAuthenticationConverter(),
- // // 授权请求(或同意)用于OAuth 2.0授权代码授权 ——授权码模式获取code
- // new OAuth2AuthorizationCodeRequestAuthenticationConverter()
- ));
- }
-
- /**
- * @Description: 注入所有自定义认证授权需要的 provider 对象
- * 1. 密码模式
- * 2. 短信登录 (暂无)
- * @param http
- * @Return: void
- */
- public void addCustomOAuth2GrantAuthenticationProvider(HttpSecurity http){
- //从shareObject中获取到授权管理业务类(主要负责管理已认证的授权信息)
- OAuth2AuthorizationService oAuth2AuthorizationService = http.getSharedObject(OAuth2AuthorizationService.class);
- //从shareObject中获取到认证管理类
- AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
-
- //new一个自定义处理密码模式的授权提供方,其中重点需要注入token生成器
- OAuth2ResourceOwnerPasswordAuthenticationProvider oAuth2ResourceOwnerPasswordAuthenticationProvider =
- new OAuth2ResourceOwnerPasswordAuthenticationProvider(authenticationManager, oAuth2AuthorizationService, oAuth2TokenGenerator());
-
- // 将自定义处理密码模式的授权提供方添加到安全配置中
- http.authenticationProvider(new PigDaoAuthenticationProvider());
- // 将自定义用户认证提供方添加到安全配置中
- http.authenticationProvider(oAuth2ResourceOwnerPasswordAuthenticationProvider);
- }
-
-
- /**
- * @Description: 令牌生成规则实现
- * @param
- * @Return: OAuth2TokenGenerator
- */
- @Bean
- public OAuth2TokenGenerator oAuth2TokenGenerator(){
-
- CustomeOAuth2AccessTokenGenerator customeOAuth2AccessTokenGenerator = new CustomeOAuth2AccessTokenGenerator();
- customeOAuth2AccessTokenGenerator.setAccessTokenCustomizer(new CustomeOAuth2TokenCustomizer());
- //new一个token生成器委托器,其中包含自定义accesstoken生成器和refreshtoken生成器
- return new DelegatingOAuth2TokenGenerator(customeOAuth2AccessTokenGenerator,new OAuth2RefreshTokenGenerator());
- }
-
- }
最终在apifox 里面进行访问,/oauth2/token是 authorization-server 默认的获取token端点:
1.请求:127.0.0.1:3001/oauth2/token
2.query:grant_type=password&scope=server&randomStr=1234567&code=1
3.body:username=admin ;password=YehdBPev
4.basic auth:Basic dGVzdDp0ZXN0




成功~
1.OAuth2Authorization的属性总记不住,要知道里面的token是存到 Map 类型里面的;
2.openfeign的使用,需要两个注解:@EnableFeignClients(basePackages="扫描注入@FeignClient注解对象")、@FeignClient。如果只添加@FeignClient注解而没有添加@EnableFeignClients,则@FeignClient注解的类就是个普通对象。
防止忘记,写一下~
