[проект pig-cloud] Понимание @Inner и @PreAuthorize, а также понимание вызова аутентификации между внутренними и внешними микросервисами

При изучении проекта pig-cloud я столкнулся с проблемой понимания аутентификации вызовов между внутренним и внешним микросервисами.Я не мог понять текст в документе Inner Annotation Making · Yuque.Прочитав исходный код и протестировав его с помощью код, я понял и резюмировал его. Остановись на минутку, боюсь, что я забуду, у меня мозгов не хватает~ (ಥ﹏ಥ)

В статье нет описания кода, а только логическое осмысление.Код можно прочитать в статьях из этой серии: [Study Notes] Запись процесса обучения проекта Leng Leng-pig, в который, вероятно, входит Authorization Server, springcloud, Mybatis Плюс ~~~_Knock code утром Blog-CSDN blog_pig проект обучения

Оглавление

A1. Понимание аутентификации вызовов между внутренними и внешними микросервисами

B1. Личное понимание

Реализация в проекте B2.pig

A2.Понимание @Inner и @PreAuthorize (только на основе кода проекта свиньи)

B1. Приведите пример для понимания

B2.Вывод: интерфейс, аннотированный @Inner(true/false), не может получить информацию об аутентификации пользователя.

B3. Проблемы безопасности внутренних вызовов аннотации @Inner

A3. Измените внутреннюю логику аутентификации вызовов микросервиса свиньи.


A1. Понимание аутентификации вызовов между внутренними и внешними микросервисами

B1. Личное понимание

Прежде всего, не глядя на проект свиньи, что касается аутентификации вызовов между внутренними и внешними микросервисами, обычно необходимо гарантировать два момента:

1. Фейковый доступ между внутренними сервисами никогда не требует аутентификации и проверки подлинности, но аутентификационная информация может быть передана;(Я ни разу не сталкивался с ситуацией, когда вызовы между внутренними сервисами требуют аутентификации) 2. Внешний доступ осуществляется
через Шлюз, который не может и не должен направлять доступ к сервису; (я никогда не сталкивался с ситуацией прямого доступа к сервису в сценарии микросервиса)

Исходя из двух вышеуказанных пунктов и нормального развития, будут следующие сценарии приложений для вызова интерфейса:

1. Внешний доступ со шлюза, внешний прямой доступ к сервису и фиктивный доступ между внутренними сервисами не требуют аутентификации и аутентификации 2.
Внешний доступ со шлюза требует аутентификации и аутентификации внешний не может получить прямой доступ к сервису фиктивный доступ между внутренними службами не требуется аутентификация и аутентификация,
3. внешний доступ со шлюза требует аутентификации и аутентификации, внешний прямой доступ к сервису требует аутентификации, внутренний сервис Feign доступа не требует аутентификации и аутентификации;

Сценарий 3 является дополнением к сценарию 2. Также должны быть ситуации, когда требуется аутентификация для внешнего прямого доступа к службе.

[Я не понимаю, что я понимаю, вы можете прочитать это в документации свиньи: Инструкции по внутренней аннотации Юкэ , я не знаю, почему я не понял его объяснения, я понял это только из исходного кода o(╥ ﹏ ╥) о]

Реализация в проекте B2.pig

После понимания сценария вызова аутентификации между внутренними и внешними микросервисами, давайте посмотрим на реализацию проекта свиньи.Логика в этом проекте заключается в реализации вышеприведенного сценария 1.2.Третий пункт не реализован.

Логика реализации кода сцены 1.2 в проекте такова:

1. Если вся аутентификация не требуется, то каждому сервису нужно только добавить этот интерфейс в белый список PermitAll цепочки фильтров безопасности ;

2. Если для внешнего доступа со шлюза требуется аутентификация и аутентификация, просто добавьте фильтр (BearerTokenAuthenticationFilter) и аутентификацию (аннотация аутентификации @PreAuthorize) в службу в соответствии с обычным завершением авторизации.

Кроме того, если внешний не может получить прямой доступ к определенному сервису, а доступ Feign между внутренними сервисами не требует проверки подлинности и проверки подлинности, интерфейс будет динамически добавлен в белый список AllowAll при запуске проекта, ицепочки фильтров безопасности

Однако, поскольку этот интерфейс уже внесен в белый список и не аутентифицирован, для предотвращения прямого внешнего доступа добавляется значение параметра @RequestHeader(SecurityConstants.FROM) для проверки того, что это внутренний вызов, то есть когда значение @Inner =true , а значение параметра @RequestHeader(SecurityConstants.FROM) может совпадать с определенным нами значением (эквивалентно паролю), доступ к нему возможен напрямую, если значение @Inner=false, то это означает, что интерфейс полностью подвергается воздействию внешнего мира.

В то же время проект pig также добавил фильтр заголовков в шлюзе gateway, который удалит значение параметра header=From.Я не совсем понимаю смысл этого шага.Это только для того, чтобы шлюз не звонил интерфейс, который может быть вызван только внутренне.Если он определен, значение параметра header=From отображается, и пользователи по-прежнему могут вызывать интерфейс @Inner(value=true), добавляя значение header=From.

A2.Понимание @Inner и @PreAuthorize (только на основе кода проекта свиньи)

B1. Приведите пример для понимания

Хорошо, прочитав теорию, давайте взглянем на практику, а заодно разберемся с двумя аннотациями @Inner и @PreAuthorize~

Позволь мне привести пример:

//以 pig-cloud 项目代码为例,看 pig-upms-biz 中的以下接口添加注解情况:

/*
*    1.这种情况下:
*    a.通过gateway网关访问时,自动去掉header=From的参数值,由于没有header=From值,会返回没有访问权限;
*    b.直接访问服务时,如果header=From值错误,则返回没有访问权限;如果header=From值正确,则访问成功;
*    c.服务间内部调用时,自动携带header=From的正确参数值,会访问成功;
*/
	@Inner
	@GetMapping("/ids")
	public R<List<Long>> listUserIdByDeptIds(@RequestParam("deptIds") Set<Long> deptIds) {
		return R.ok(userService.listUserIdByDeptIds(deptIds));
	}

/*
*    2.这种情况下:
*    d.通过gateway网关访问时,自动去掉header=From的参数值,由于@Inner的value=false,直接访问成功;
*    e.直接访问服务时,由于@Inner的value=false,直接访问成功;
*    f.服务间内部调用时,无论是否携带header=From的参数值,由于@Inner的value=false,直接访问成功;
*/
	@Inner(false)
	@GetMapping("/ids")
	public R<List<Long>> listUserIdByDeptIds(@RequestParam("deptIds") Set<Long> deptIds) {
		return R.ok(userService.listUserIdByDeptIds(deptIds));
	}

/*
*    3.这种情况下:
*    无论用哪种方式访问,都会返回没有访问权限!
*    原因:首先先要知道@Inner和@PreAuthorize注解都是有个切面的,并且@Inner的切面执行顺序在@PreAuthorize的切面之前。当前请求在上面的 b.c.d.e.f 情况中都能够顺利通过@Inner注解的切面,但是在@PreAuthorize的切面里面永远都不会通过!因为永远拿不到已认证的SecurityContextHolder.getContext().getAuthentication()!
*/
	@Inner(true/false)
    @PreAuthorize("@pms.hasPermission('任意值权限标识')")
	@GetMapping("/ids")
	public R<List<Long>> listUserIdByDeptIds(@RequestParam("deptIds") Set<Long> deptIds) {
		return R.ok(userService.listUserIdByDeptIds(deptIds));
	}

Приведенный выше пример 3. включает логику аутентификации аутентифицированного пользователя.

Сторона ресурсов в проекте pig использует spring-security-oauth2-resource-server для реализации аутентификации пользователя. Его логика заключается в том, что когда приходит запрос, сначала получить токен в запросе через фильтр BearerTokenAuthenticationFilter, затем отнести токен на авторизационный конец, чтобы проверить токен и получить аутентифицированную информацию о пользователе, а затем положить информацию о пользователе в себя. SecurityContextHolder для облегчения последующего использования запроса в бизнесе.

Здесь в BearerTokenAuthenticationFilter Resolver будет использоваться для получения токена сначала, а затем будет инициирована аутентификация до конца авторизации, если он получен, и следующий фильтр будет выполнен, если он не получен. И проект свиньи настроил класс реализации этого Resolver! И в этом есть логика, если текущий запрос является вайтлистом, возвращать null напрямую!

Видя это, я понимаю, что на стороне ресурса (сторона авторизации не настроена с ресурсом), пока интерфейс аннотирован @Inner, никогда не будет информации для аутентификации пользователя!

Иллюстрация, не забывай~

B2.Вывод: интерфейс, аннотированный @Inner(true/false), не может получить информацию об аутентификации пользователя.

@Inner: Убедитесь, что внутренние вызовы между службами не аутентифицированы (к вызову должен быть добавлен правильный заголовок), и что нет полномочий для доступа к службам через шлюз, а также что нет полномочий для прямого доступа к службам (только при нормальные обстоятельства, если запрос несет заголовок) И значение правильное, доступ будет успешным [Это уязвимость, я также видел этот контрольный вопрос на свинобазе, lengleng ответил: "Принцип минимальной эксплуатации и обслуживания будет не выставлять другие порты, кроме этих портов», подробности см. в этой проблеме: внутренняя аннотация, проблемы безопасности внутренних вызовов, проблема № I5S2U9 lengleng/pig — Gitee.com ])

@Inner(flase): доступ может быть успешным при любых обстоятельствах;

Но помните, что интерфейсы с аннотацией @Inner(true/false) не могут получать информацию об аутентификации пользователя! Таким образом, @Inner и @PreAuthorize, используемые вместе, всегда не возвращают разрешения!

Сторона авторизации не будет использовать аннотацию @PreAuthorize.

Но @Inner можно использовать для предотвращения вызова службами интерфейса конца авторизации и предотвращения внешних вызовов.

B3. Проблемы безопасности внутренних вызовов аннотации @Inner

Добавьте каталог, будьте осторожны, чтобы не забыть (〝▼皮▼)

Я также видел эту проблему безопасности на складе свиней. Ленгленг ответил: «Принцип минимальной эксплуатации и обслуживания не будет раскрывать другие порты, кроме этих портов» . · длина/свинья - Gitee.com】)

A3. Измените внутреннюю логику аутентификации вызовов микросервиса свиньи.

3. Внешний доступ со шлюза требует аутентификации и аутентификации, внешний прямой доступ к  сервису требует аутентификации, притворный доступ между внутренними сервисами не требует аутентификации и аутентификации;

Но мы можем модифицировать его логику и реализовать 3. на базе 1.2.(но лазейка все же есть!).

Три шага:

1. Сначала удалите аспект @Inner host, этот аспект больше не нужен, логика @Inner используется только как идентификатор, указывающий, что этот интерфейс используется для вызовов содержимого микросервиса. 

2. Измените класс конфигурации белого списка PermitAllUrlProperties, измените существующий атрибут urls и добавьте только путь к элементу конфигурации: к этому типу интерфейса можно получить доступ без аутентификации; добавьте еще один атрибут innerUrls, чтобы добавить только путь к интерфейсу, отмеченный @Inner: этот тип интерфейса выделен Доступ без аутентификации для внутренних вызовов (то есть добавить путь динамического перехвата в afterPropertiesSet() к innerUrls)

3. Снова измените класс PigBearerTokenExtractor.Если запрос соответствует атрибуту urls в PermitAllUrlProperties, он будет выпущен напрямую без аутентификации; если запрос соответствует атрибуту innerUrls в PermitAllUrlProperties и имеется заголовок (From) == правильное значение, он эквивалентно внутреннему вызову напрямую, а не аутентификации и освобождению; если запрос соответствует свойству innerUrls PermitAllUrlProperties и имеет заголовок (From)! =Верное значение, это означает, что не внутренние вызовы должны быть аутентифицированы, и аутентификация не будет снята, если аутентификация не удалась; (В этом случае внутренний вызов микросервиса также может быть аутентифицирован без заголовка (From), но с токеном)

предупреждать! предупреждать! предупреждать! В этом случае, если значение параметра header(From) открыто, вы можете получить прямой доступ без аутентификации! ! !

Конечно, также можно аутентифицировать все микросервисы внутри, тогда приведенная выше логика не нужна, и нужно только добавить токены для внутренних вызовов~

Посмотрите на реальную бизнес-среду

おすすめ

転載: blog.csdn.net/vaevaevae233/article/details/127548631