具有Spring Security过滤器链,重定向循环的Wicket授权

时间:2018-07-20 16:20:24

标签: java authentication spring-security authorization wicket

我想用小票@AuthorizationInstantiation保护我的页面,并且该应用程序应受Spring Security Filter Chain保护。

我在网络上找到了一些示例,但没有一个与我想要实现该应用的方式相匹配。

我想在Wicket页面中使用类似@AuthorizeInstantiation({"user", "admin"})之类的东西,以后再使用其他Wicket特定的方式来授权我的应用程序。

当我将应用程序部署到Tomcat并在浏览器中调用登录页面(或其他页面)时,会发生无尽的重定向

我想MySecurityConfigurerAdapter#configure(HttpSecurity http)

有问题

Wicket不会调用我在authenticate(username, password)的实现中使用的方法getRoles()AuthenticatedWebSession

下面是我的代码的摘录。完整的MCVE在Gitlab

上可用

WebSecurityConfigurerAdapter的实施

@Configuration
@EnableWebSecurity
public class MySecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws
            Exception {
        authenticationManagerBuilder.userDetailsService(new MyUserDetailsService());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //@formatter:off
        http
           .csrf().disable()
           .authorizeRequests()
                    .antMatchers("/favicon.ico").permitAll()
                    .antMatchers("/logout_success").permitAll()
                    .antMatchers("login").permitAll()
           .and()
           .formLogin()
                    .loginPage("/login")
                    .permitAll()
                    .loginProcessingUrl("/login")
           .and()
           .addFilter(new SecurityContextPersistenceFilter()).securityContext();

        //@formatter:on
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManagerBean();
    }
}

UserDetailsService的实施

public class MyUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Collection<MyAuthority> authorities = new HashSet<>();
        MyAuthority admin = new MyAuthority("admin");
        MyAuthority user = new MyAuthority("user");
        MyAuthority guest = new MyAuthority("guest");

        switch (username) {
            case "tim":
            case "steve":
                authorities.add(admin);
                authorities.add(user);
                authorities.add(guest);
                break;
            case "craig":
                authorities.add(user);
                authorities.add(guest);
                break;
            case "phil":
                authorities.add(guest);
                break;
            default:
                throw new UsernameNotFoundException("user \"" + username + "\" unknown");
        }
        return new User(username, "123456", authorities);
    }

    class MyAuthority implements GrantedAuthority {
        private final String role;

        MyAuthority(String r) {
            role = r;
        }

        @Override
        public String getAuthority() {
            return role;
        }
    }
}

AbstractSecurityWebApplicationInitializer的实施

public class MySecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer
{
    public MySecurityWebApplicationInitializer()
    {
        super(MySecurityConfigurerAdapter.class);
    }

    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext)
    {
        super.beforeSpringSecurityFilterChain(servletContext);
    }

    @Override
    protected void afterSpringSecurityFilterChain(ServletContext servletContext)
    {
        super.afterSpringSecurityFilterChain(servletContext);

        Filter myWicketFilter=new WicketFilter(new MyApplication())
        {
            @Override
            public void init(boolean isServlet, FilterConfig filterConfig) throws ServletException
            {
                setFilterPath("");
                super.init(isServlet, filterConfig);
            }
        };

        FilterRegistration.Dynamic wicketRegistration;
        wicketRegistration = servletContext.addFilter("myWicketFilter", myWicketFilter);
        wicketRegistration.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "*");
    }
}

门票申请

public class MyApplication extends AuthenticatedWebApplication {
    @Override
    protected void init() {
        super.init();
        getComponentInstantiationListeners().add(new SpringComponentInjector(this));
        getSecuritySettings().setAuthorizationStrategy(new AnnotationsRoleAuthorizationStrategy(this));
        mountPage("/login", Login.class);
        mountPage("/start", UserStart.class);
        mountPage("/public", Public.class);
        mountPage("/admin", Admin.class);
    }

    @Override
    protected Class<? extends AbstractAuthenticatedWebSession> getWebSessionClass() {
        return MyWebSession.class;
    }

    @Override
    protected Class<? extends WebPage> getSignInPageClass() {
        return Login.class;
    }

    @Override
    public Class<? extends Page> getHomePage() {
        return UserStart.class;
    }
}

AuthenticatedWebSession的实施

public class MyWebSession extends AuthenticatedWebSession {
    @SpringBean
    private
    AuthenticationManager authenticationManager;

    public MyWebSession(Request request) {
        super(request);
        Injector.get().inject(this);
    }

    @Override
    protected boolean authenticate(String username, String password) {
        boolean authenticated;
        try {
            Authentication authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(username
                            , password));
            SecurityContextHolder.getContext().setAuthentication(authentication);
            authenticated = authentication.isAuthenticated();
            System.out.println("Authentication: "+authenticated+", User \""+username+"\"");
        }
        catch (AuthenticationException e) {
            authenticated = false;
            System.err.println("Login mit \"" + username + "\" fehlgeschlagen, " + e.getMessage());
        }
        return authenticated;
    }

    @Override
    public Roles getRoles() {
        Roles roles = new Roles();
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication.isAuthenticated()) {
            for (GrantedAuthority authority : authentication.getAuthorities()) {
                roles.add(authority.getAuthority());
            }
        }
        System.out.println("Roles: "+roles.toString());
        return roles;
    }
}

更新

我在/中插入了丢失的.antMatchers("login").permitAll(),但这没有帮助。

当我致电http://localhost:8080/context_name/login时,我会看到登录页面。提交表单后,会显示StackOverflowError

java.lang.StackOverflowError
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:163)
    org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:494)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199)
    org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:494)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199)
    org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:494)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199)
    org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:494)

这是Spring Security调试日志的摘录:

********************************************************************
**********        Security debugging is enabled.       *************
**********    This may include sensitive information.  *************
**********      Do not use in a production system!     *************
********************************************************************


23-Jul-2018 16:42:40.561 INFO [RMI TCP Connection(3)-127.0.0.1] org.springframework.web.context.ContextLoader.initWebApplicationContext Root WebApplicationContext: initialization completed in 936 ms
[RMI TCP Connection(3)-127.0.0.1] INFO org.apache.wicket.Application - [myWicketFilter] init: Wicket core library initializer
[RMI TCP Connection(3)-127.0.0.1] INFO org.apache.wicket.Application - [myWicketFilter] init: Wicket extensions initializer
[RMI TCP Connection(3)-127.0.0.1] INFO org.apache.wicket.protocol.http.WebApplication - [myWicketFilter] Started Wicket version 8.0.0 in DEVELOPMENT mode
********************************************************************
*** WARNING: Wicket is running in DEVELOPMENT mode.              ***
***                               ^^^^^^^^^^^                    ***
*** Do NOT deploy to your live server(s) without changing this.  ***
*** See Application#getConfigurationType() for more information. ***
********************************************************************
[2018-07-23 04:42:40,779] Artifact wicketAuthSpringSec:war: Artifact is deployed successfully
[2018-07-23 04:42:40,779] Artifact wicketAuthSpringSec:war: Deploy took 3.465 milliseconds
23-Jul-2018 16:42:40.951 INFO [http-apr-8080-exec-4] Spring Security Debugger.info 

************************************************************

Request received for GET '/':

org.apache.catalina.connector.RequestFacade@16ec26d8

servletPath:/
pathInfo:null
headers: 
user-agent: IntelliJ IDEA/181.5281.24
accept-encoding: gzip
cache-control: no-cache
pragma: no-cache
host: localhost:8080
accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
connection: keep-alive


Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  LogoutFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]


************************************************************


23-Jul-2018 16:42:41.013 INFO [http-apr-8080-exec-6] Spring Security Debugger.info 

************************************************************

Request received for GET '/start':

org.apache.catalina.connector.RequestFacade@16ec26d8

servletPath:/start
pathInfo:null
headers: 
user-agent: IntelliJ IDEA/181.5281.24
accept-encoding: gzip
cache-control: no-cache
pragma: no-cache
host: localhost:8080
accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
connection: keep-alive


Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  LogoutFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]


************************************************************


Roles: ROLE_ANONYMOUS
23-Jul-2018 16:42:41.075 INFO [http-apr-8080-exec-6] Spring Security Debugger.info 

************************************************************

New HTTP session created: 547244D1E42D71DA11F9BAD666EBFC3F

Call stack: 

    at org.springframework.security.web.debug.Logger.info(Logger.java:44)
    at org.springframework.security.web.debug.DebugRequestWrapper.getSession(DebugFilter.java:166)
    at org.springframework.security.web.debug.DebugRequestWrapper.getSession(DebugFilter.java:177)
    at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:231)
    at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:231)
    at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:231)
    at org.apache.wicket.session.HttpSessionStore.getHttpSession(HttpSessionStore.java:85)
    at org.apache.wicket.session.HttpSessionStore.getSessionId(HttpSessionStore.java:146)
    at org.apache.wicket.Session.bind(Session.java:270)
    at org.apache.wicket.RestartResponseAtInterceptPageException$InterceptData.set(RestartResponseAtInterceptPageException.java:140)
    at org.apache.wicket.RestartResponseAtInterceptPageException.<init>(RestartResponseAtInterceptPageException.java:82)
    at org.apache.wicket.RestartResponseAtInterceptPageException.<init>(RestartResponseAtInterceptPageException.java:68)
    at org.apache.wicket.authroles.authentication.AuthenticatedWebApplication.restartResponseAtSignInPage(AuthenticatedWebApplication.java:103)
    at org.apache.wicket.authroles.authentication.AuthenticatedWebApplication.onUnauthorizedInstantiation(AuthenticatedWebApplication.java:81)
    at org.apache.wicket.Application$1.onInstantiation(Application.java:279)
    at org.apache.wicket.application.ComponentInstantiationListenerCollection$1.notify(ComponentInstantiationListenerCollection.java:38)
    at org.apache.wicket.application.ComponentInstantiationListenerCollection$1.notify(ComponentInstantiationListenerCollection.java:34)
    at org.apache.wicket.util.listener.ListenerCollection.notify(ListenerCollection.java:80)
    at org.apache.wicket.application.ComponentInstantiationListenerCollection.onInstantiation(ComponentInstantiationListenerCollection.java:33)
    at org.apache.wicket.Component.<init>(Component.java:679)
    at org.apache.wicket.MarkupContainer.<init>(MarkupContainer.java:178)
    at org.apache.wicket.Page.<init>(Page.java:171)
    at org.apache.wicket.Page.<init>(Page.java:135)
    at org.apache.wicket.markup.html.WebPage.<init>(WebPage.java:74)
    at de.example.app.pages.UserStart.<init>(UserStart.java:10)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:175)
    at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:67)
    at org.apache.wicket.DefaultMapperContext.newPageInstance(DefaultMapperContext.java:90)
    at org.apache.wicket.core.request.handler.PageProvider$Provision.getPage(PageProvider.java:380)
    at org.apache.wicket.core.request.handler.PageProvider.getPageInstance(PageProvider.java:171)
    at org.apache.wicket.request.handler.render.PageRenderer.getPage(PageRenderer.java:78)
    at org.apache.wicket.request.handler.render.WebPageRenderer.respond(WebPageRenderer.java:231)
    at org.apache.wicket.core.request.handler.RenderPageRequestHandler.respond(RenderPageRequestHandler.java:202)
    at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:912)
    at org.apache.wicket.request.RequestHandlerExecutor.execute(RequestHandlerExecutor.java:65)
    at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:283)
    at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:253)
    at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:221)
    at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:262)
    at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:204)
    at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:286)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
    at org.springframework.security.web.debug.DebugFilter.invokeWithWrappedRequest(DebugFilter.java:90)
    at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:77)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:670)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2508)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2497)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)


************************************************************


23-Jul-2018 16:42:41.091 INFO [http-apr-8080-exec-8] Spring Security Debugger.info 

************************************************************

Request received for GET '/login':

org.apache.catalina.connector.RequestFacade@16ec26d8

servletPath:/login
pathInfo:null
headers: 
user-agent: IntelliJ IDEA/181.5281.24
accept-encoding: gzip
cache-control: no-cache
pragma: no-cache
host: localhost:8080
accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
connection: keep-alive


Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  LogoutFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]


************************************************************


23-Jul-2018 16:42:41.216 INFO [http-apr-8080-exec-8] Spring Security Debugger.info 

************************************************************

New HTTP session created: 55EDC4A7C5B989B253923455CE54965A

1 个答案:

答案 0 :(得分:0)

找到StackOverflowError Trying to Expose AuthenticationManager in Spring WebSecurityConfigurerAdapter后,我解决了核心问题。

无限循环是由覆盖authenticationManager()而不是authenticationManagerBean()引起的。与userDetailsServiceBean()相同。

public class MySecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Autowired(name="userDetailsService")
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws
            Exception {
        authenticationManagerBuilder.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       ....
    }

    @Bean(name="authenticationManager")
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    /* not working:
    public AuthenticationManager authenticationManager() {  ...  }
    */

    @Bean(name="userDetailsService")
    @Override
    public UserDetailsService userDetailsServiceBean() {
        return new MyUserDetailsService();
    }
    // not working:  UserDetailsService userDetailsService() { ... }
}