• No6-4.从零搭建spring-cloud-alibaba微服务框架,解决微服务间的不鉴权调用等(四,no6-4)


       代码地址与接口看总目录:【学习笔记】记录冷冷-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安全注解实现)

    目录

    A9.解决微服务间的不鉴权调用(可修改外部访问鉴权逻辑~)

    步骤:

    测试:


    A9.解决微服务间的不鉴权调用(可修改外部访问鉴权逻辑~)

    微服务间调用问题,和 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. //1.
    2. @Target({ ElementType.METHOD, ElementType.TYPE })
    3. @Retention(RetentionPolicy.RUNTIME)
    4. @Documented
    5. public @interface Inner {
    6. /**
    7. * 是否AOP统一处理
    8. * @return false, true
    9. */
    10. boolean value() default true;
    11. /**
    12. * 需要特殊判空的字段(预留)
    13. * @return {}
    14. */
    15. String[] field() default {};
    16. }
    1. //2.修改这个类,使他实现 InitializingBean 类,这样再创建 bean 之前就能够修改对他进行以下操作
    2. @Slf4j
    3. @ConfigurationProperties(prefix = "security.oauth2.ignore")
    4. public class PermitAllUrlProperties implements InitializingBean {
    5. private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
    6. @Getter
    7. @Setter
    8. private List urls = new ArrayList<>();
    9. @Override
    10. public void afterPropertiesSet() throws Exception {
    11. //拿到 bean ,RequestMappingHandlerMapping的作用是在容器启动后将系统中所有控制器方法的请求条件(RequestMappingInfo)和控制器方法(HandlerMethod)的对应关系注册到RequestMappingHandlerMapping Bean的内存中,
    12. RequestMappingHandlerMapping mapping = SpringUtil.getBean("requestMappingHandlerMapping");
    13. //拿到映射的mapper
    14. Map map = mapping.getHandlerMethods();
    15. map.keySet().forEach(info -> {
    16. HandlerMethod handlerMethod = map.get(info);
    17. // 获取方法上边的注解 替代path variable 为 *。这里注意,如果是 /user/{id} 修改为: /user/* ,如果是 /user/id 还是: /user/id
    18. //​todo 必须注意,如果是 /{id} 会修改为: /* ,就相当于,当前类同级下的匹配路径都会被添加到ignore-urls中!!!!
    19. Inner method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Inner.class);
    20. Optional.ofNullable(method).ifPresent(inner -> info.getPatternsCondition().getPatterns()
    21. .forEach(url -> urls.add(ReUtil.replaceAll(url, PATTERN, "*"))));
    22. // 获取类上边的注解, 替代path variable 为 *。这里注意,如果是 /user/{id} 修改为: /user/* ,如果是 /user/id 还是: /user/id
    23. Inner controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Inner.class);
    24. Optional.ofNullable(controller).ifPresent(inner ->
    25. info.getPatternsCondition().getPatterns().forEach(url -> urls.add(ReUtil.replaceAll(url, PATTERN, "*"))));
    26. });
    27. }
    28. }
    1. //3.@Inner 注解切面
    2. @Slf4j
    3. @Aspect
    4. @RequiredArgsConstructor
    5. public class PigSecurityInnerAspect implements Ordered {
    6. private final HttpServletRequest request;
    7. @SneakyThrows
    8. @Around("@within(inner) || @annotation(inner)")
    9. public Object around(ProceedingJoinPoint point, Inner inner) {
    10. // 实际注入的inner实体由表达式后一个注解决定,即是方法上的@Inner注解实体,若方法上无@Inner注解,则获取类上的
    11. if (inner == null) {
    12. Class clazz = point.getTarget().getClass();
    13. inner = AnnotationUtils.findAnnotation(clazz, Inner.class);
    14. }
    15. //拿到 header(From) 参数值
    16. String header = request.getHeader(SecurityConstants.FROM);
    17. //是 aop 统一处理,并且 header(From) 值又正确,就跳过直接执行方法;否则抛出无权限异常
    18. if (inner.value() && !StrUtil.equals(SecurityConstants.FROM_SECRET_VALUE, header)) {
    19. log.warn("访问接口 {} 没有权限", point.getSignature().getName());
    20. throw new AccessDeniedException("Access is denied");
    21. }
    22. return point.proceed();
    23. }
    24. @Override
    25. public int getOrder() {
    26. return Ordered.HIGHEST_PRECEDENCE + 1;
    27. }
    28. }
    29. //--------------
    30. //添加到 /META-INF/string.factoies
    31. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    32. com.pig4cloud.pig.common.security.service.PigRedisOAuth2AuthorizationService,\
    33. com.pig4cloud.pig.common.security.service.PigRemoteRegisteredClientRepository,\
    34. com.pig4cloud.pig.common.security.component.PigSecurityInnerAspect
    1. //4.网关的全局拦截器,作用所有的微服务
    2. public class PigRequestGlobalFilter implements GlobalFilter, Ordered {
    3. @Override
    4. public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    5. // 1. 清洗请求头中from 参数;修改请求里面的内容然后再重新构建一下
    6. ServerHttpRequest request = exchange.getRequest().mutate()
    7. .headers(httpHeaders -> httpHeaders.remove(SecurityConstants.FROM)).build();
    8. //将修改后的请求放入 ServerWebExchange 里面
    9. addOriginalRequestUrl(exchange, request.getURI());
    10. return chain.filter(exchange);
    11. }
    12. @Override
    13. public int getOrder() {
    14. return 10;
    15. }
    16. }
    1. //5. @Inner 注解的value默认是他true表示只有远程调用才可以使用,若value=false表示任意的访问都使用
    2. @RestController
    3. @RequiredArgsConstructor
    4. @RequestMapping("/user")
    5. public class UserController {
    6. private final SysUserService userService;
    7. ...
    8. /**
    9. * @Description: 获取指定用户名的用户全部信息,用于用户认证
    10. * @param username
    11. * @Return: com.pig4cloud.pig.common.core.util.R
    12. */
    13. @Inner
    14. @GetMapping("/info/{username}")
    15. public R info(@PathVariable String username) {
    16. SysUser sysUser = userService.getOne(Wrappers.lambdaQuery().eq(SysUser::getUsername, username));
    17. if(sysUser == null){
    18. return R.failed("用户不存在");
    19. }
    20. //这里拿到用户的其他关联信息,并赋值给VO
    21. UserInfoDTO userInfoDTO = userService.getUserInfo(sysUser);
    22. return R.ok(userInfoDTO);
    23. }
    24. ...
    25. }
    1. //6.在 nacos 上的 application.yml 中添加
    2. # Spring 相关
    3. spring:
    4. mvc:
    5. pathmatch:
    6. matching-strategy: ant_path_matcher

    但是要注意:凡是被 @Inner 标注的接口都不会获取用户认证信息,并且会被加入 security 白名单!

    测试:


  • 相关阅读:
    “银行家算法”大揭秘!在前端表格中利用自定义公式实现“四舍六入五成双”
    Vue Router的介绍
    FME——湘源规划用地CAD带指标导入ArcGIS数据库
    【基于Arduino的仿生蚂蚁机器人】
    找不到实时聊天软件?给你推荐电商企业都在用的!
    数组与链表算法-矩阵算法
    unity shaderGraph实例-可交互草地
    睡眠不好怎么调理?
    洗地机哪款最好用?口碑最好的家用洗地机推荐
    MySQL如果实现隔离级别-MVCC
  • 原文地址:https://blog.csdn.net/vaevaevae233/article/details/127582907