国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

websocket配合spring-security使用token認證

CODING / 2283人閱讀

摘要:最后發現每一個在連接端點之前都會發送一個請求用于保證該服務是存在的。而該請求是程序自動發送的自能自動攜帶數據,無法發送自定義。問題是我們的是使用自定義實現的認證。所以該方法不成立,所以只能讓自己認證。

使用框架介紹

spring boot 1.4.3.RELEASE

spring websocket 4.3.5.RELEASE

spring security 4.1.3.RELEASE

sockjs-client 1.0.2

stompjs 2.3.3

項目介紹

由于公司需要使用websocket主動給前端用戶推送消息,公司的項目是使用jhipster自動生成的微服務項目,而spring boot本身就集成了websocket,這樣我們不用自己處理所有的網絡細節代碼。我們的項目主要為:
前端 - nodeJS代理 - 后端 - 計算系統(由于我們公司是做云計算的,計算系統是一個底層系統)
項目的主要流程是:

遇到的問題

由于我們使用的是spring security oauth2 來進行認證,而且我們需要吧websocket消息推送給指定用戶,這樣為了保證websocket和http協議使用的同一套認證系統,我們就必須要把websocket認證集成到spring security中。

第一個問題認證403錯誤

首先貼出websocket的配置代碼

public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    private final static Logger LOG = LoggerFactory.getLogger(WebSocketConfig.class);

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/api/v1/socket/send");  // 推送消息前綴
        registry.setApplicationDestinationPrefixes("/api/v1/socket/req"); // 應用請求前綴
        registry.setUserDestinationPrefix("/user");//推送用戶前綴
    }



    /**
     * 建立連接的端點
     * @param registry
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/api/v1/socket/fallback").setAllowedOrigins("*").withSockJS().setInterceptors(httpSessionHandshakeInterceptor());
    }
}

第一次在打開websocket的時候發現三次握手都沒有出現就直接報403,最后仔細看錯誤信息發現錯誤信息的鏈接為:/api/v1/socket/fallback/info,而且該請求使用的是http請求不是websocket請求。最后發現每一個websocket在連接端點之前都會發送一個http GET請求用于保證該服務是存在的。而該請求是程序自動發送的自能自動攜帶cookie數據,無法發送自定義header。

spring boot自帶的認證是:如果/api/v1/socket/fallback/info該請求通過認證,那么websocket的所有請求以及發送全部自動綁定該認證用戶。如果我們想辦法讓/api/v1/socket/fallback/info請求通過認證,那么接下來所有的問題都將解決。問題是我們的token是使用自定義header實現的認證。所以該方法不成立,所以只能讓websocket自己認證。

為了解決/api/v1/socket/fallback/info請求的403問題我在安全配置中加入.authorizeRequests().antMatchers("/api/v1/socket/fallback/**").permitAll()這樣第一步判斷服務是否存在就解決了,這里離解決websocket的認證問題只是第一步。

第二個問題:如果發送token給后端

stomp 客戶端可以直接在websocket請求中加入自定義header,如下:

let socket = new SockJS("/api/v1/socket/fallback")
let stompClient = Stomp.over(socket)
let token = localStorage.getItem("Auth-Token") // eslint-disable-line
stompClient.connect({"Auth-Token": token}, frame => {
  stompClient.subscribe("/user/api/v1/socket/send/greetings", data => {
    // TODO
  })
})
第三個問題:后端如何認證

我們在創建連接的時候前端需要將token發送到后端,現在我們已經將token發送到后端了,但是后端如何接受并處理token得到認證數據呢?帶著這個問題開始google吧!http://stackoverflow.com/questions/39422053/spring-4-x-token-based-websocket-sockjs-fallback-authentication這個鏈接正好解決了我的問題,

UPDATE 2016-12-13 : the issue referenced below is now marked fixed, so the hack below is no longer necessary which Spring 4.3.5 or above. See https://github.com/spring-projects/spring-framework/blob/master/src/asciidoc/web-websocket.adoc#token-based-authentication.

原來這個問題在4.3.5版本中已經被繼承進去了,查看自己的版本是4.3.4,不解釋直接升級版本到4.3.5,然后加如代碼

@EnableWebSocketMessageBroker
public class MyConfig extends AbstractWebSocketMessageBrokerConfigurer {

  @Override
  public void configureClientInboundChannel(ChannelRegistration registration) {
    registration.setInterceptors(new ChannelInterceptorAdapter() {

        @Override
        public Message preSend(Message message, MessageChannel channel) {

            StompHeaderAccessor accessor =
                MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);

            if (StompCommand.CONNECT.equals(accessor.getCommand())) {
                String jwtToken = accessor.getFirstNativeHeader("Auth-Token");
                    if (StringUtils.isNotEmpty(jwtToken)) {
                        UserAuthenticationToken authToken = tokenService.retrieveUserAuthToken(jwtToken);
                        SecurityContextHolder.getContext().setAuthentication(authToken);
                        accessor.setUser(authToken);
                    }
            }

            return message;
        }
    });
  }
}

開始測試,發現還是報錯MissingCsrfTokenException,然后開始debug代碼,發現代碼錯誤的代碼為:

public final class CsrfChannelInterceptor extends ChannelInterceptorAdapter {
    private final MessageMatcher matcher;

    public CsrfChannelInterceptor() {
        this.matcher = new SimpMessageTypeMatcher(SimpMessageType.CONNECT);
    }

    public Message preSend(Message message, MessageChannel channel) {
        if(!this.matcher.matches(message)) {
            return message;
        } else {
            Map sessionAttributes = SimpMessageHeaderAccessor.getSessionAttributes(message.getHeaders());
            CsrfToken expectedToken = sessionAttributes == null?null:(CsrfToken)sessionAttributes.get(CsrfToken.class.getName());
            if(expectedToken == null) {  // 在這里為null
                throw new MissingCsrfTokenException((String)null);  //報錯
            } else {
                String actualTokenValue = SimpMessageHeaderAccessor.wrap(message).getFirstNativeHeader(expectedToken.getHeaderName());
                boolean csrfCheckPassed = expectedToken.getToken().equals(actualTokenValue);
                if(csrfCheckPassed) {
                    return message;
                } else {
                    throw new InvalidCsrfTokenException(expectedToken, actualTokenValue);
                }
            }
        }
    }
}

仔細查看里面的數據,原來這里是需要在header中存放一些數據,于是乎將configureClientInboundChannel方法修正為:

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.setInterceptors(new ChannelInterceptorAdapter() {
            @Override
            public Message preSend(Message message, MessageChannel channel) {
                StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
                if (StompCommand.CONNECT.equals(accessor.getCommand())) {
                    String jwtToken = accessor.getFirstNativeHeader("Auth-Token");
                    LOG.debug("webSocket token is {}", jwtToken);
                    if (StringUtils.isNotEmpty(jwtToken)) {
                        Map sessionAttributes = SimpMessageHeaderAccessor.getSessionAttributes(message.getHeaders());
                        sessionAttributes.put(CsrfToken.class.getName(), new DefaultCsrfToken("Auth-Token", "Auth-Token", jwtToken));
                        UserAuthenticationToken authToken = tokenService.retrieveUserAuthToken(jwtToken);
                        SecurityContextHolder.getContext().setAuthentication(authToken);
                        accessor.setUser(authToken);
                    }
                }
                return message;
            }
        });
    }

然后修改websocket安全配置為:

@Configuration
public class WebsocketSecurityConfiguration extends AbstractSecurityWebSocketMessageBrokerConfigurer {

    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages.anyMessage().permitAll();
    }

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

這樣websocket 集成spring boot token的認證就搞定了。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66357.html

相關文章

  • 基于spring-security-oauth2實現單點登錄(持續更新)

    摘要:認證服務器和瀏覽器控制臺也沒有報錯信息。這里簡單介紹下如何查閱源碼,首先全局搜索自己的配置因為這個地址是認證服務器請求授權的,所以,請求認證的過濾器肯定包含他。未完待續,下一篇介紹資源服務器和認證服務器的集成。 基于spring-security-oauth2-實現單點登錄 文章代碼地址:鏈接描述可以下載直接運行,基于springboot2.1.5,springcloud Green...

    妤鋒シ 評論0 收藏0
  • 前后端分離項目 — 基于SpringSecurity OAuth2.0用戶認證

    摘要:前言現在的好多項目都是基于移動端以及前后端分離的項目,之前基于的前后端放到一起的項目已經慢慢失寵并淡出我們視線,尤其是當基于的微服務架構以及單頁面應用流行起來后,情況更甚。使用生成是什么請自行百度。 1、前言 現在的好多項目都是基于APP移動端以及前后端分離的項目,之前基于Session的前后端放到一起的項目已經慢慢失寵并淡出我們視線,尤其是當基于SpringCloud的微服務架構以及...

    QLQ 評論0 收藏0
  • [譯] Elixir、Phoenix、Absinthe、GraphQL、React 和 Apollo

    摘要:對于每個案例,我們插入所需要的測試數據,調用需要測試的函數并對結果作出斷言。我們將這個套接字和用戶返回以供我們其他的測試使用。 原文地址:Elixir, Phoenix, Absinthe, GraphQL, React, and Apollo: an absurdly deep dive - Part 2 原文作者:Zach Schneider 譯文出自:掘金翻譯計劃 本文永久鏈接:gi...

    Cympros 評論0 收藏0
  • spring security登錄、登出、認證異常返回值的自定義實現

    摘要:在整個學習過程中,我最關心的內容有號幾點,其中一點是前后端分離的情況下如何不跳轉頁面而是返回需要的返回值。登錄成功,不跳轉頁面,返回自定義返回值在官方文檔第節,有這么一段描述要進一步控制目標,可以使用屬性作為的替代。 在整個學習過程中,我最關心的內容有號幾點,其中一點是【前后端分離的情況下如何不跳轉頁面而是返回需要的返回值】。下面就說一下學習結果,以xml配置位李。 登錄成功,不跳轉頁...

    mushang 評論0 收藏0

發表評論

0條評論

CODING

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<