источник
В стандартном RABC разрешения должны поддерживать динамическую конфигурацию, Spring Security по умолчанию по умолчанию для договора разрешений в коде. Реальные бизнес -сценарии обычно требуют, чтобы разрешения на доступ к роле были динамически настроены, то есть для настройки ролей доступа, соответствующих URL -адресам во время выполнения.
Основываясь на весенней безопасности, как достичь этого требования?
Самый простой способ - настроить фильтр для выполнения разрешения, но это отделено от структуры безопасности Spring. Как внедрить его элегантно на основе весенней безопасности?
Обзор авторизации весной безопасности
Spring Security FilterChainProxy используется в качестве фильтра для регистрации в Интернете. FilterChainProxy содержит несколько встроенных фильтров одновременно. Во-первых, нам нужно понять различные фильтры, встроенные в Spring Security:
| Псевдоним | Фильтр класс | Элемент пространства имен или атрибут |
|---|---|---|
| Channel_filter | ChannelProcessingFilter | http/recept-url@требуется канал |
| Security_Context_filter | SecurityContextPersistenceFilter | http |
| CONDURRENT_SESSION_FILTER | ConcurrentsessionFilter | сессионное управление/контроль параллелизма |
| Headers_filter | HeaderWriterFilter | http/заголовки |
| Csrf_filter | Csrffilter | http/csrf |
| Logout_filter | LogoutFilter | http/logout |
| X509_filter | X509AuthenticationFilter | http/x509 |
| Pre_auth_filter | AbstractPreauthatedCockessingFilter Подклассы | N/a |
| Cas_filter | CasauthenticationFilter | N/a |
| Form_login_filter | Usernamepasswordauthenticationfilter | http/form-login |
| Basic_auth_filter | BasicAuthenticationFilter | http/http-basic |
| Servlet_api_support_filter | SecurityContextholderaWarereQuestFilter | http/@servlet-api-provision |
| Jaas_api_support_filter | Jaasapiintegrationfilter | http/@jaas-api-provision |
| Помните_me_filter | Помните MeauthenticationFilter | http/momply-me |
| Anonymous_filter | Anonymoushauthenticationfilter | http/anonymous |
| Session_management_filter | SessionManagementFilter | сессионное управление |
| Exception_translation_filter | ExceptionTranslationFilter | http |
| Filter_security_interceptor | FiltersecurityInterceptor | http |
| Switch_user_filter | SwitchUserFilter | N/a |
Наиболее важным является FiltersecurityInterceptor, который реализует основную логику аутентификации, и самый основной код здесь:
Protected InterceptorStatustokene Inclocation (Object Object) {// Получить разрешения, необходимые для доступа к коллекции URL <configattribute> attributes = this.obtainsecuritymetadatasource () .getattributes (object); Аутентификация аутентифицирована = Authenticateifrequired (); // аутентификация через AccessDecisionManager try {this.AccessDecisionManager.docide (аутентифицированный, объект, атрибуты); } catch (AccessDiedException AccessDidieDexception) {publishevent (new AuthorizationFailureEvent (объект, атрибуты, аутентифицированные, AccessDenieDexception)); бросить AccepleDiedException; } if (debug) {logger.debug ("Авторизация успешно"); } if (publishauthorizationsuccessful ");} if (publishauthorizationuccess) {publishevent (new AuthorizedEvent (Object, Attributes, Authenticated));} // Попытка работать как различная аутентификация пользователя runas = runasmanager.buildrunas (Authentricated, outributes); {logger.debug ("Runasmanager не изменил объект аутентификации"); SecurityContextholder.getContext ();Как видно из вышеперечисленного, для достижения динамической аутентификации мы можем начать с двух аспектов:
Давайте посмотрим, как это реализовать отдельно.
Пользовательский AccessDecisionManager
Все три официальных AccessDecisionManagers основаны на AccessDecisionVoter для реализации аутентификации разрешений, поэтому нам нужно только настроить AccessDecisionVoter.
Настройка в основном реализует интерфейс AccessDecisionVoter. Мы можем реализовать следующие официальные Rolevoter:
открытый класс RoleBasedVoter реализует AccessDecisionVoter <Object> {@Override Public Boolean Supports (ConfigatTribute Attribute) {return True; } @Override public int hoge (аутентификация аутентификации, объект объекта, коллекция <configatTribute> attributes) {if (аутентификация == null) {return access_dyed; } int result = access_abstain; Коллекция <? расширяет wreatedAuthority> власти = ExtractAuthorities (аутентификация); for (configattribt attribute: attributes) {if (attribute.getAttribute () == null) {продолжение; } if (this.supports (attribute)) {result = access_denied; // Попытка найти сопоставление предоставленных полномочий для (wreatedAuthority Authority: Outhorations) {if (attribute.getattribute (). Equals (atorment.getauthority ())) {return access_granted; }}}} return result; } Коллекция <? Extends wreatedAuthority> ExtractAuthorities (аутентификация аутентификации) {return authentication.getAuthorities (); } @Override public boolean sulps (class clazz) {return true; }}Как добавить динамические разрешения?
Тип объекта объекта в vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) - FilterInvocation, и вы можете получить URL -адрес текущего запроса через getRequesturl:
FilterInvocation fi = (FilterInvocation) объект; String url = fi.getRequesturl ();
Поэтому здесь много места для расширения. Вы можете динамически загрузить его из БД, а затем оценить конфигурацию URL -адреса.
Как использовать этот RoleBasedVoter? Используйте метод AccessDecisionManager для настройки в конфигурации. Мы должны использовать официальную единогласную основу, а затем добавить индивидуальную RoleBasedVoter.
@Enablewebsecurity @enableglobalmethodsecurity (prepostenabled = true, securedenabled = true) открытый класс SecurityConfiguration Extends WebseCurityConfigurerAdapter {@Override Protected void configure (httpsecurity http) exception {http.addfilterbefor .exceptionHandling () .AuthenticationEntryPoint (проблемы Upport) .AccessDidiedHandler (проблемы). и () .csrf () .diSable () .Headers () .FrameOptions () .disable (). и () .sessionManagement () .sessionCreationpolicy (). // Пользовательский AccessDecisionManager .AccessDecisionManager (AccessDecisionManager ()). И () .Apply (SecurityConfigurerAdapter ()); } @Bean Public AccessDecisionManager AccessDecisionManager () {List <AccessDecisionVoter <? Extends Object >> DeciessVoters = arrays.aslist (new WebExpressionVoter (), // new Rolevoter (), New RoleBasedVoter (), New AuthenticatedVoter ()); вернуть новые единогласные (DeciessVoters); }Настроить SecurityMetAdatasource
Пользовательский FilterInvocationsecurityMetadatasource должен только реализовать интерфейс и динамически загружать правила от DB в интерфейсе.
Чтобы повторно использовать определения в коде, мы можем взять SecurityMetAdatasource, сгенерированный в коде, и передать в конструкторе в конструкторе по умолчанию.
Общедоступный класс AppFilterInvocationsecurityMetAdatasource реализует org.springframework.security.web.access.intercept.filterinvocationsemetaDatasource {Private FilterInvocationsecurityMetadatasource supermetadatasource; @Override Public Collection <CONCINATTRIBUTE> GETALLCONFIGATTRIBUTES () {return NULL; } public appfilterInvocationsecurityMetAdatasource (FilterInvocationsecurityMetAdatasource ExpressionBasedFilterInvocationSecurityMetadAsource) {this.supermetAdatasource = ExpressedBasedFilterInvocationSecuteMetAdatasource; // Конфигурация разрешения на загрузку TODO из базы данных} Частный конечный AntPathMatcher antPathMatcher = new AntPathMatcher (); // Здесь вам нужно загрузить частную окончательную карту <string, string> urlrolemap = new Hashmap <string, string> () {{put ("/open/**", "role_anonymous"); put ("/health", "role_anonymous"); put ("/restart", "role_admin"); put ("/demo", "role_user"); }}; @Override public Collection <configatTribute> getAttributes (объект объекта) Throws allogalargumentException {filterinvocation fi = (filterinvocation) объект; String url = fi.getRequesturl (); for (map.Entry <string, string> intry: urlroleMap.EntrySet ()) {if (antPathMatcher.match (entry.getKey (), url)) {return securityConfig.createList (entry.getValue ()); }} // возвращать конфигурацию по умолчанию, определенную кодом return supermetadatasource.getattributes (object); } @Override public boolean поддерживает (class <?> Clazz) {return filterinvocation.class.isassignablefrom (clazz); }}Как его использовать? В отличие от AccessDecisionManager, ExpressionUrlauthorizationConfigurer не предоставляет установленный метод для установки фильтрации, как можно сделать?
Откройте для себя метод расширения withObjectPostProcessor, с помощью которого настраивает объект PostPostProcessor, который обрабатывает тип FiltersEcurityInterceptor, вы можете изменить FiltersEcurityInterceptor.
@Enablewebsecurity @enableglobalmethodsecurity (prepostenabled = true, securedenabled = true) открытый класс SecurityConfiguration Extends WebseCurityConfigurerAdapter {@Override Protected void configure (httpsecurity http) exception {http.addfilterbefor .exceptionHandling () .AuthenticationEntryPoint (проблемы Upport) .AccessDidiedHandler (проблемы). и () .csrf () .diSable () .Headers () .FrameOptions () .disable (). и () .sessionManagement () .sessionCreationpolicy (). // Пользовательский FilterInvocationSecurityMetAdatasource .withobjectPostProcessor (новый ObjectPostProcessor <FiltersEcurityInterceptor> () {@Override public <O Extends FiltersEcurityInterceptor> o PostProcess (O FSI) { fsi.setsecuritymetadatasource (mysecuritymetadatasource (fsi.getsecuritymetadatasource ()); } @Bean public appfilterinvocationsecuritymetadatasource mysecuritymetadatasource (filterinvocationsecuritymetadatasource filterinvocationsemateadatasource) {appFilterInvocationAdataDataSource SecurityMetAsource = new Appfilterinvocationsecuritymetadatasource (FilterinvocationsecurityMetadatasource); return SecurityMetAdatasource;}краткое содержание
В этой статье представлены два метода реализации динамических разрешений на основе безопасности пружины. Одним из них является настройка AccessDecisionManager, а другой - настроить FilterInvocationsecurityMetadatasource. Вы можете выбрать гибко в соответствии с вашими потребностями в реальных проектах.
Дальнейшее чтение:
Архитектура безопасности весной и анализа исходного кода
Суммировать
Вышеуказанное - все содержание этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.