Spring Securityでは、以下のようにintercept-urlタグを使用して、URLへのアクセスを定義します。
<intercept-url pattern="/**" access="ROLE_ADMIN" />
<intercept-url pattern="/student" access="ROLE_STUDENT" />
これはapplicationContext-security.xml
にハードコードされています。代わりに、データベーステーブルからアクセス値を読み取ります。自分のUserDetailsService
を定義し、ログインしたユーザーのロールをデータベースから読み取りました。実行時にこれらのロールをURLパターンに割り当てるにはどうすればよいですか?
Spring-securityのFilterInvocationSecurityMetadataSourceParserクラス(ソースコードを使用してSTSでCtrl/Cmd + Shift + Tを試行)は、intercept-urlタグを解析し、SecurityMetadataSourceを拡張するFilterInvocationSecurityMetadataSourceを実装するDefaultFilterInvocationSecurityMetadataSourceを拡張するExpressionBasedFilterInvocationSecurityMetadataSourceのインスタンスを作成します。
私が行ったことは、FilterInvocationSecurityMetadataSource OptionsFromDataBaseFilterInvocationSecurityMetadataSourceを実装するカスタムクラスを作成することです。 DefaultFilterInvocationSecurityMetadataSourceをベースとして使用して、urlMatcherを使用し、support()メソッドなどを実装しました。
次に、これらのメソッドを実装する必要があります。
コレクションgetAttributes(Objectオブジェクト)。データベースにアクセスし、保護されている「オブジェクト」(通常はアクセスするURL)を検索して、許可されたConfigAttribute(通常はROLE)を取得します。
ブール値のサポート(クラスclazz)
コレクションgetAllConfigAttributes()
後者は起動時に呼び出され、現時点では適切に構成されていない可能性があるため、注意してください(つまり、使用しているものに応じて、データソースまたは永続コンテキストが自動接続されているため)。 Web環境での解決策は、applicationContext-security.xmlの前にapplicationContext.xmlをロードするようにweb.xmlのcontextConfigLocationを構成することです。
最後のステップは、このBeanをロードするようにapplicationContext-security.xmlをカスタマイズすることです。
そのために、セキュリティ名前空間ではなく、このファイルで通常のBeanを使用しました。
<beans:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<filter-chain-map path-type="ant">
<filter-chain pattern="/images/*" filters="none" />
<filter-chain pattern="/resources/**" filters="none" />
<filter-chain pattern="/**" filters="
securityContextPersistenceFilter,
logoutFilter,
basicAuthenticationFilter,
exceptionTranslationFilter,
filterSecurityInterceptor"
/>
</filter-chain-map>
</beans:bean>
関連するすべてのBeanを定義する必要があります。例えば:
<beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<beans:property name="authenticationManager" ref="authenticationManager"></beans:property>
<beans:property name="accessDecisionManager" ref="affirmativeBased"></beans:property>
<beans:property name="securityMetadataSource" ref="optionsFromDataBaseFilterInvocationSecurityMetadataSource"></beans:property>
<beans:property name="validateConfigAttributes" value="true"/></beans:bean>
私はそれが十分に説明された答えではないことを知っていますが、見た目ほど難しくはありません。
ばね源をベースとして使用するだけで、必要なものが得られます。
データベースのデータを使用してデバッグすることは、非常に役立ちます。
実際、Spring Security 3.2は http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/faq.html#faq-dynamicに従ってこれを行うことを推奨していません-url-metadata
しかし、カスタムaccessDecisionManagerで名前空間のhttp要素を使用することは可能です(ただしエレガントではありません)。
構成は次のようになります。
<http pattern="/login.action" security="none"/>
<http pattern="/media/**" security="none"/>
<http access-decision-manager-ref="accessDecisionManager" >
<intercept-url pattern="/**" access="ROLE_USER"/>
<form-login login-page="/login.action"
authentication-failure-url="/login?error=1"
default-target-url="/console.action"/>
<logout invalidate-session="true" delete-cookies="JSESIONID"/>
<session-management session-fixation-protection="migrateSession">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" expired-url="/login.action"/>
</session-management>
<!-- NO ESTA FUNCIONANDO, los tokens no se ponen en el request!
<csrf />
-->
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="test" password="test" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<beans:bean id="accessDecisionManager" class="openjsoft.core.services.security.auth.CustomAccessDecisionManager">
<beans:property name="allowIfAllAbstainDecisions" value="false"/>
<beans:property name="decisionVoters">
<beans:list>
<beans:bean class="org.springframework.security.access.vote.RoleVoter"/>
</beans:list>
</beans:property>
</beans:bean>
CustomAccessDecisionManagerは...
public class CustomAccessDecisionManager extends AbstractAccessDecisionManager {
...
public void decide(Authentication authentication, Object filter,
Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
if ((filter == null) || !this.supports(filter.getClass())) {
throw new IllegalArgumentException("Object must be a FilterInvocation");
}
String url = ((FilterInvocation) filter).getRequestUrl();
String contexto = ((FilterInvocation) filter).getRequest().getContextPath();
Collection<ConfigAttribute> roles = service.getConfigAttributesFromSecuredUris(contexto, url);
int deny = 0;
for (AccessDecisionVoter voter : getDecisionVoters()) {
int result = voter.vote(authentication, filter, roles);
if (logger.isDebugEnabled()) {
logger.debug("Voter: " + voter + ", returned: " + result);
}
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
return;
case AccessDecisionVoter.ACCESS_DENIED:
deny++;
break;
default:
break;
}
}
if (deny > 0) {
throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",
"Access is denied"));
}
// To get this far, every AccessDecisionVoter abstained
checkAllowIfAllAbstainDecisions();
}
...
}
GetConfigAttributesFromSecuredUrisが特定のURLのフォームDB deロールを取得する場所
私は同じ問題を抱えていますが、基本的には、intercept-urlのリストを他のspringsecurity構成セクションから分離しておきます。最初はアプリケーション構成に属し、後者は製品(コア、プラグイン)構成に属します。
この問題に関して、春のJIRAには proposal があります。
Springsecurity名前空間の使用をあきらめたくないので、これに対処するためにいくつかの可能な解決策を考えていました。
Intercept-urlのリストを動的に作成するには、filterSecurityInterceptorにsecuritymetadatasourceオブジェクトを挿入する必要があります。 SpringSecurityスキーマを使用すると、FilterSecurityInterceptorのインスタンスがHttpBuilderクラスによって作成されます。次のような回避策を使用する場合ほど、スキーマ構成ファイルで定義されたプロパティとしてsecuritymetadatasourceを渡す方法はありません。
どう思いますか?
私のために働く簡単な解決策。
<intercept-url pattern="/**/**" access="#{@customAuthenticationProvider.returnStringMethod}" />
<intercept-url pattern="/**" access="#{@customAuthenticationProvider.returnStringMethod}" />
customAuthenticationProviderはBeanです
<beans:bean id="customAuthenticationProvider"
class="package.security.CustomAuthenticationProvider" />
customAuthenticationProviderクラスのcreateメソッド:
public synchronized String getReturnStringMethod()
{
//get data from database (call your method)
if(condition){
return "IS_AUTHENTICATED_ANONYMOUSLY";
}
return "ROLE_ADMIN,ROLE_USER";
}
これは、intercept-urlエントリのリストを他のSpringセキュリティ構成から分割するために適用したソリューションです。
<security:custom-filter ref="parancoeFilterSecurityInterceptor"
before="FILTER_SECURITY_INTERCEPTOR" />
........
<bean id="parancoeFilterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor" >
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="securityMetadataSource" ref="securityMetadataSource"/>
</bean>
Bean securityMetadataSourceは、同じ構成ファイルまたは別の構成ファイルに配置できます。
<security:filter-security-metadata-source
id="securityMetadataSource" use-expressions="true">
<security:intercept-url pattern="/admin/**"
access="hasRole('ROLE_ADMIN')" />
</security:filter-security-metadata-source>
もちろん、インターフェースFilterInvocationSecurityMetadataSourceを実装することにより、独自のsecurityMetadataSource Beanを実装することを決定できます。このようなもの:
<bean id="securityMetadataSource" class="mypackage.MyImplementationOfFilterInvocationSecurityMetadataSource" />
お役に立てれば。
これは、Spring Security 3.2で実行できる方法です。
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public SecurityConfigDao securityConfigDao() {
SecurityConfigDaoImpl impl = new SecurityConfigDaoImpl() ;
return impl ;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
/* get a map of patterns and authorities */
Map<String,String> viewPermissions = securityConfigDao().viewPermissions() ;
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry interceptUrlRegistry = http
.authorizeRequests().antMatchers("/publicAccess/**")
.permitAll();
for (Map.Entry<String, String> entry: viewPermissions.entrySet()) {
interceptUrlRegistry.antMatchers(entry.getKey()).hasAuthority(entry.getValue());
}
interceptUrlRegistry.anyRequest().authenticated()
.and()
...
/* rest of the configuration */
}
}