代码地址与接口看总目录:【学习笔记】记录冷冷-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);
第二篇文章:
No6.从零搭建spring-cloud-alibaba微服务框架,实现数据库调用、用户认证与授权等(二,no6-2)_清晨敲代码的博客-CSDN博客
文章包括:
6.添加 mysql 数据库调用,并使用mybatis-plus操作;
7.在认证模块添加用户认证,基于oauth2的自定义密码模式(已认证用户是基于自定义token加redis持久化,不是session);
第三篇文章:
No6-3.从零搭建spring-cloud-alibaba微服务框架,实现资源端用户认证与授权等(三,no6-3)
8.在资源端模块添加用户认证,基于授权端的认证token添加逻辑(但是没有处理微服务间的不鉴权调用,微服务间的调用接口都是白名单呢!);
本篇内容包括:
9.解决微服务间的不鉴权调用(可修改外部访问鉴权逻辑~)
剩余包括(会有变动):
10.添加用户鉴权逻辑(基于RBAC逻辑,使用springsecuiry安全注解实现)
目录
微服务间调用问题,和 pig 项目里面的实现逻辑,在另一篇文里面总结了,就不复述了,并且修改外部访问鉴权逻辑,也在这篇文章里面可以看:【pig-cloud项目】关于@Inner和@PreAuthorize的理解,以及微服务内外部间的调用认证鉴权理解
1.添加 @Inner ;
2.修改 PermitAllUrlProperties ,再创建bean之前,记得包被@Inner注解的方法或类加进白名单中;
3.添加 PigSecurityInnerAspect ,添加微服务内部调用的 header(From) 值;并且添加到 /META-INF/string.factoies 中;
4.在 pig-gateway 模块添加PigRequestGlobalFilter全局过滤器,将请求中的 header(From) 值全部清除。
5.在需要的接口上添加 @Inner 注解;
6.给 pig-upms 模块的配置文件 application.yml 或者nacos中的配置文件中修改,springmvc接口匹配规则由默认的path_pattern_parser修改为ant_path_matcher;
- //1.
-
- @Target({ ElementType.METHOD, ElementType.TYPE })
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface Inner {
-
- /**
- * 是否AOP统一处理
- * @return false, true
- */
- boolean value() default true;
-
- /**
- * 需要特殊判空的字段(预留)
- * @return {}
- */
- String[] field() default {};
-
- }
- //2.修改这个类,使他实现 InitializingBean 类,这样再创建 bean 之前就能够修改对他进行以下操作
-
- @Slf4j
- @ConfigurationProperties(prefix = "security.oauth2.ignore")
- public class PermitAllUrlProperties implements InitializingBean {
-
- private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
-
- @Getter
- @Setter
- private List
urls = new ArrayList<>(); -
- @Override
- public void afterPropertiesSet() throws Exception {
- //拿到 bean ,RequestMappingHandlerMapping的作用是在容器启动后将系统中所有控制器方法的请求条件(RequestMappingInfo)和控制器方法(HandlerMethod)的对应关系注册到RequestMappingHandlerMapping Bean的内存中,
- RequestMappingHandlerMapping mapping = SpringUtil.getBean("requestMappingHandlerMapping");
- //拿到映射的mapper
- Map
map = mapping.getHandlerMethods(); -
- map.keySet().forEach(info -> {
- HandlerMethod handlerMethod = map.get(info);
-
- // 获取方法上边的注解 替代path variable 为 *。这里注意,如果是 /user/{id} 修改为: /user/* ,如果是 /user/id 还是: /user/id
- //todo 必须注意,如果是 /{id} 会修改为: /* ,就相当于,当前类同级下的匹配路径都会被添加到ignore-urls中!!!!
- Inner method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Inner.class);
- Optional.ofNullable(method).ifPresent(inner -> info.getPatternsCondition().getPatterns()
- .forEach(url -> urls.add(ReUtil.replaceAll(url, PATTERN, "*"))));
-
-
- // 获取类上边的注解, 替代path variable 为 *。这里注意,如果是 /user/{id} 修改为: /user/* ,如果是 /user/id 还是: /user/id
- Inner controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Inner.class);
- Optional.ofNullable(controller).ifPresent(inner ->
- info.getPatternsCondition().getPatterns().forEach(url -> urls.add(ReUtil.replaceAll(url, PATTERN, "*"))));
- });
- }
- }
- //3.@Inner 注解切面
-
- @Slf4j
- @Aspect
- @RequiredArgsConstructor
- public class PigSecurityInnerAspect implements Ordered {
-
- private final HttpServletRequest request;
-
- @SneakyThrows
- @Around("@within(inner) || @annotation(inner)")
- public Object around(ProceedingJoinPoint point, Inner inner) {
- // 实际注入的inner实体由表达式后一个注解决定,即是方法上的@Inner注解实体,若方法上无@Inner注解,则获取类上的
- if (inner == null) {
- Class> clazz = point.getTarget().getClass();
- inner = AnnotationUtils.findAnnotation(clazz, Inner.class);
- }
- //拿到 header(From) 参数值
- String header = request.getHeader(SecurityConstants.FROM);
- //是 aop 统一处理,并且 header(From) 值又正确,就跳过直接执行方法;否则抛出无权限异常
- if (inner.value() && !StrUtil.equals(SecurityConstants.FROM_SECRET_VALUE, header)) {
- log.warn("访问接口 {} 没有权限", point.getSignature().getName());
- throw new AccessDeniedException("Access is denied");
- }
- return point.proceed();
- }
-
- @Override
- public int getOrder() {
- return Ordered.HIGHEST_PRECEDENCE + 1;
- }
-
- }
-
- //--------------
- //添加到 /META-INF/string.factoies
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.pig4cloud.pig.common.security.service.PigRedisOAuth2AuthorizationService,\
- com.pig4cloud.pig.common.security.service.PigRemoteRegisteredClientRepository,\
- com.pig4cloud.pig.common.security.component.PigSecurityInnerAspect
- //4.网关的全局拦截器,作用所有的微服务
-
- public class PigRequestGlobalFilter implements GlobalFilter, Ordered {
-
- @Override
- public Mono
filter(ServerWebExchange exchange, GatewayFilterChain chain) { - // 1. 清洗请求头中from 参数;修改请求里面的内容然后再重新构建一下
- ServerHttpRequest request = exchange.getRequest().mutate()
- .headers(httpHeaders -> httpHeaders.remove(SecurityConstants.FROM)).build();
-
- //将修改后的请求放入 ServerWebExchange 里面
- addOriginalRequestUrl(exchange, request.getURI());
-
- return chain.filter(exchange);
- }
-
- @Override
- public int getOrder() {
- return 10;
- }
- }
- //5. @Inner 注解的value默认是他true表示只有远程调用才可以使用,若value=false表示任意的访问都使用
-
- @RestController
- @RequiredArgsConstructor
- @RequestMapping("/user")
- public class UserController {
-
- private final SysUserService userService;
- ...
-
- /**
- * @Description: 获取指定用户名的用户全部信息,用于用户认证
- * @param username
- * @Return: com.pig4cloud.pig.common.core.util.R
- */
- @Inner
- @GetMapping("/info/{username}")
- public R
info(@PathVariable String username) { - SysUser sysUser = userService.getOne(Wrappers.
lambdaQuery().eq(SysUser::getUsername, username)); - if(sysUser == null){
- return R.failed("用户不存在");
- }
-
- //这里拿到用户的其他关联信息,并赋值给VO
- UserInfoDTO userInfoDTO = userService.getUserInfo(sysUser);
- return R.ok(userInfoDTO);
- }
- ...
-
- }
- //6.在 nacos 上的 application.yml 中添加
- # Spring 相关
- spring:
- mvc:
- pathmatch:
- matching-strategy: ant_path_matcher
但是要注意:凡是被 @Inner 标注的接口都不会获取用户认证信息,并且会被加入 security 白名单!




