Spring安全websocket和HTTP身份验证/授权

时间:2015-06-05 09:23:43

标签: spring spring-security spring-boot spring-websocket spring-messaging

摘要 我想通过STOMP实现websocket通信。在第一次(HTTP请求)websocket握手时验证用户,并使用此Principal稍后授权websocket消息。

问题 系统在第一次尝试连接到websocket端点(HTTP握手的时间)时对客户端进行身份验证。我的Spring安全过滤器和身份验证提供程序完成其工作并正确验证客户端。在此之后,我可以检查客户端是否获得了角色,我的身份验证对象也存储在SecurityContext中。 (此时建立了websocket连接,并且已经丢弃了HTTP协议。)从第一个websocket通信但是我得到的Authentication对象是Anonymous,因为SecurityContextHolder以某种方式被清除,因为 SecurityContextChannelInterceptor 清除它。

Spring文档声明如下:http://docs.spring.io/autorepo/docs/spring-security/current/reference/htmlsingle/#websocket-authentication

  

WebSockets重用与WebSocket连接时在HTTP请求中找到的相同身份验证信息。这意味着HttpServletRequest上的Principal将被移交给WebSockets。如果您使用的是Spring Security,则会自动覆盖HttpServletRequest上的Principal。

我非常简单的过滤器

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

    try {


        Authentication authResult =
                new CertAuthenticationToken(null, Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN")));

        authResult = getAuthenticationManager().authenticate(authResult);

        if (authResult.isAuthenticated()) {
            SecurityContextHolder.getContext().setAuthentication(authResult);
            LOGGER.info("Client was authenticated.");
        }
        chain.doFilter(request, response);

    } catch (AuthenticationException ae) {
        LOGGER.error("Client was not authenticated. {}", ae);
        SecurityContextHolder.clearContext();
        onUnsuccessfulAuthentication((HttpServletRequest) request, (HttpServletResponse) response, ae);
        throw ae;
    }
}

我非常简单的身份验证提供程序

 public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        authentication.setAuthenticated(true);
        return authentication;
    }

Spring boot与1.3.0.BUILD-SNAPSHOT版本一起使用。一个额外的依赖是spring-security-messaging with 4.0.1.RELEASE version,我在默认的spring boot依赖项旁边使用它。

感谢任何问题的帮助。

应用程序安全性:

@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {


    @Autowired
    AuthenticationManager authenticationManager;


    @Bean
    CertAuthenticationFilter certAuthenticationFilter() {
        return new CertAuthenticationFilter(authenticationManager);
    }

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

        http
            .csrf().disable()
            .authorizeRequests().expressionHandler(new         CustomExpressionHandler()) 
            .antMatchers("/hello", "/websocket/**").access( "isCustomAuthorized()" )
            .and()
            .httpBasic()
            .and()
            .addFilter( certAuthenticationFilter() ); 

    }

}

身份验证安全性:

@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
public class AuthenticationSecurity extends
        GlobalAuthenticationConfigurerAdapter {

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(new CertHeaderAuthenticationProvider());
        auth.authenticationProvider(new CustomWebsocketAuthenticationProvider());
        auth.inMemoryAuthentication();
    }
}

Websocket安全性:

@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
    @Autowired
    AuthenticationManager authenticationManager;

    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages
                .simpTypeMatchers(SimpMessageType.CONNECT).access("isCustomAuthorized()");
    }

    @Override
    public ChannelSecurityInterceptor inboundChannelSecurity() {
        ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(
                inboundMessageSecurityMetadataSource());
        channelSecurityInterceptor.setAccessDecisionManager(setupDecisionManager());
        return channelSecurityInterceptor;
    }


    private AffirmativeBased setupDecisionManager() {
        MessageExpressionVoter messageExpressionVoter = new MessageExpressionVoter<Object>();
        messageExpressionVoter.setExpressionHandler(new CustomMessageSecurityExpressionHandler());
        List<AccessDecisionVoter<? extends Object>> voters = new ArrayList<AccessDecisionVoter<? extends Object>>();
        voters.add(messageExpressionVoter);
        AffirmativeBased manager = new AffirmativeBased(voters);
        return manager;
    }

    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }
    }

0 个答案:

没有答案