最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring中Websocket身份驗(yàn)證和授權(quán)的實(shí)現(xiàn)

 更新時(shí)間:2023年08月18日 10:23:58   作者:timi先生  
在Web應(yīng)用開(kāi)發(fā)中,安全一直是非常重要的一個(gè)方面,本文主要介紹了Spring中Websocket身份驗(yàn)證和授權(quán)的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下

一、需要了解的事項(xiàng)

  • http和WebSocket的安全鏈和安全配置是完全獨(dú)立的。
  • SpringAuthenticationProvider根本不參與 Websocket 身份驗(yàn)證。
  • 將要給出的示例中,身份驗(yàn)證不會(huì)發(fā)生在 HTTP 協(xié)商端點(diǎn)上,因?yàn)?JavaScript STOMP(websocket)庫(kù)不會(huì)隨 HTTP 請(qǐng)求一起發(fā)送必要的身份驗(yàn)證標(biāo)頭。
  • 一旦在 CONNECT 請(qǐng)求上設(shè)置,用戶(hù)( simpUser) 將被存儲(chǔ)在 websocket 會(huì)話(huà)中,并且以后的消息將不再需要進(jìn)行身份驗(yàn)證。

二、依賴(lài)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-messaging</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-messaging</artifactId>
</dependency>

三、WebSocket 配置

3.1 、簡(jiǎn)單的消息代理

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends WebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(final MessageBrokerRegistry config) {
        config.enableSimpleBroker("/queue/topic");
        config.setApplicationDestinationPrefixes("/app");
    }
    @Override
    public void registerStompEndpoints(final StompEndpointRegistry registry) {
        registry.addEndpoint("stomp"); 
        setAllowedOrigins("*")
    }
}

3.2 、Spring安全配置

由于 Stomp 協(xié)議依賴(lài)于第一個(gè) HTTP 請(qǐng)求,因此需要授權(quán)對(duì) stomp 握手端點(diǎn)的 HTTP 調(diào)用。

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(final HttpSecurity http) throws Exception
        http.httpBasic().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests().antMatchers("/stomp").permitAll()
                .anyRequest().denyAll();
    }
}

然后創(chuàng)建一個(gè)負(fù)責(zé)驗(yàn)證用戶(hù)身份的服務(wù)。

@Component
public class WebSocketAuthenticatorService {
    public UsernamePasswordAuthenticationToken getAuthenticatedOrFail(final String  username, final String password) throws AuthenticationException {
        if (username == null || username.trim().isEmpty()) {
            throw new AuthenticationCredentialsNotFoundException("Username was null or empty.");
        }
        if (password == null || password.trim().isEmpty()) {
            throw new AuthenticationCredentialsNotFoundException("Password was null or empty.");
        }
        if (fetchUserFromDb(username, password) == null) {
            throw new BadCredentialsException("Bad credentials for user " + username);
        }
        return new UsernamePasswordAuthenticationToken(
                username,
                null,
                Collections.singleton((GrantedAuthority) () -> "USER") // 必須給至少一個(gè)角色
        );
    }
}

接著需要?jiǎng)?chuàng)建一個(gè)攔截器,它將設(shè)置“simpUser”標(biāo)頭或在 CONNECT 消息上拋出“AuthenticationException”。

@Component
public class AuthChannelInterceptorAdapter extends ChannelInterceptor {
    private static final String USERNAME_HEADER = "login";
    private static final String PASSWORD_HEADER = "passcode";
    private final WebSocketAuthenticatorService webSocketAuthenticatorService;
    @Inject
    public AuthChannelInterceptorAdapter(final WebSocketAuthenticatorService webSocketAuthenticatorService) {
        this.webSocketAuthenticatorService = webSocketAuthenticatorService;
    }
    @Override
    public Message<?> preSend(final Message<?> message, final MessageChannel channel) throws AuthenticationException {
        final StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
        if (StompCommand.CONNECT == accessor.getCommand()) {
            final String username = accessor.getFirstNativeHeader(USERNAME_HEADER);
            final String password = accessor.getFirstNativeHeader(PASSWORD_HEADER);
            final UsernamePasswordAuthenticationToken user = webSocketAuthenticatorService.getAuthenticatedOrFail(username, password);
            accessor.setUser(user);
        }
        return message;
    }
}

請(qǐng)注意:preSend() 必須返回 UsernamePasswordAuthenticationToken,Spring 安全鏈中會(huì)對(duì)此進(jìn)行測(cè)試。如果UsernamePasswordAuthenticationToken構(gòu)建沒(méi)有通過(guò)GrantedAuthority,則身份驗(yàn)證將失敗,因?yàn)闆](méi)有授予權(quán)限的構(gòu)造函數(shù)自動(dòng)設(shè)置authenticated = false 這是一個(gè)重要的細(xì)節(jié),在 spring-security 中沒(méi)有記錄。

最后再創(chuàng)建兩個(gè)類(lèi)來(lái)分別處理授權(quán)和身份驗(yàn)證。

@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE + 99)
public class WebSocketAuthenticationSecurityConfig extends  WebSocketMessageBrokerConfigurer {
    @Inject
    private AuthChannelInterceptorAdapter authChannelInterceptorAdapter;
    @Override
    public void registerStompEndpoints(final StompEndpointRegistry registry) {
        // 這里不用給任何東西
    }
    @Override
    public void configureClientInboundChannel(final ChannelRegistration registration) {
        registration.setInterceptors(authChannelInterceptorAdapter);
    }
}

請(qǐng)注意:這@Order是至關(guān)重要的,它允許我們的攔截器首先在安全鏈中注冊(cè)。

@Configuration
public class WebSocketAuthorizationSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
    @Override
    protected void configureInbound(final MessageSecurityMetadataSourceRegistry messages) {
        // 添加自己的映射
        messages.anyMessage().authenticated();
    }
    // 這里請(qǐng)自己按需求修改
    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }
}

之后編寫(xiě)客戶(hù)端進(jìn)行連接,我們就可以這樣指定客戶(hù)端進(jìn)行消息的發(fā)送。

    @MessageMapping("/greeting")
    public void greetingReturn(@Payload Object ojd){
         simpMessagingTemplate.convertAndSendToUser(username,"/topic/greeting",ojd);
    }

到此這篇關(guān)于Spring中Websocket身份驗(yàn)證和授權(quán)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Spring Websocket身份驗(yàn)證和授權(quán)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java后端限制頻繁請(qǐng)求和重復(fù)提交的實(shí)現(xiàn)

    Java后端限制頻繁請(qǐng)求和重復(fù)提交的實(shí)現(xiàn)

    很多用戶(hù)會(huì)請(qǐng)求過(guò)于頻繁或者是多次重復(fù)提交數(shù)據(jù),本文主要介紹了Java后端限制頻繁請(qǐng)求和重復(fù)提交的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Java獲取客戶(hù)端真實(shí)IP地址經(jīng)典寫(xiě)法詳解

    Java獲取客戶(hù)端真實(shí)IP地址經(jīng)典寫(xiě)法詳解

    在Web開(kāi)發(fā)中,獲取客戶(hù)端的真實(shí)IP地址是一個(gè)常見(jiàn)需求,本文將分別給出經(jīng)典寫(xiě)法(基于工具類(lèi)/條件判斷)和Lambda寫(xiě)法(基于函數(shù)式接口?+?流式處理)的實(shí)現(xiàn),并進(jìn)行對(duì)比
    2026-04-04
  • mybatis直接執(zhí)行完整sql及踩坑解決

    mybatis直接執(zhí)行完整sql及踩坑解決

    MyBatis可通過(guò)select標(biāo)簽執(zhí)行動(dòng)態(tài)SQL,DQL用List<LinkedHashMap>接收結(jié)果,DML用int處理,注意防御SQL注入,優(yōu)先使用#{}參數(shù),資源目錄需規(guī)范路徑,避免綁定異常;數(shù)據(jù)庫(kù)字段避免關(guān)鍵字,防止轉(zhuǎn)義問(wèn)題
    2025-09-09
  • Java實(shí)現(xiàn)開(kāi)箱即用的redis分布式鎖

    Java實(shí)現(xiàn)開(kāi)箱即用的redis分布式鎖

    這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)開(kāi)箱即用的基于redis的分布式鎖,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以收藏一下
    2022-12-12
  • SpringBoot @Retryable注解方式

    SpringBoot @Retryable注解方式

    這篇文章主要介紹了SpringBoot @Retryable注解方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • Spring啟動(dòng)時(shí)實(shí)現(xiàn)初始化有哪些方式?

    Spring啟動(dòng)時(shí)實(shí)現(xiàn)初始化有哪些方式?

    今天給大家?guī)?lái)的文章是關(guān)于Spring的相關(guān)知識(shí),文章圍繞著Spring啟動(dòng)時(shí)實(shí)現(xiàn)初始化有哪些方式展開(kāi),文中有非常詳細(xì)的介紹,需要的朋友可以參考下
    2021-06-06
  • java rocketmq--消息的產(chǎn)生(普通消息)

    java rocketmq--消息的產(chǎn)生(普通消息)

    這篇文章主要介紹了java rocketmq--消息的產(chǎn)生(普通消息),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下
    2019-06-06
  • java后端請(qǐng)求兌現(xiàn)request的中文亂碼問(wèn)題解決

    java后端請(qǐng)求兌現(xiàn)request的中文亂碼問(wèn)題解決

    文章主要講述了在處理處理方案工作中遇到中文亂碼問(wèn)題的解決過(guò)程,通過(guò)復(fù)現(xiàn)和分析亂碼問(wèn)題,發(fā)現(xiàn)是由于解碼規(guī)則和后端服務(wù)編碼不一致導(dǎo)致的,最終通過(guò)修改過(guò)濾器中的編碼設(shè)置解決了問(wèn)題
    2025-02-02
  • Mybatis中注解@MapKey的使用方式

    Mybatis中注解@MapKey的使用方式

    MyBatis使用@MapKey注解進(jìn)行連表查詢(xún),返回一個(gè)Map集合,Map的key為每條記錄的主鍵或指定字段,value為該記錄的字段名稱(chēng)和字段值
    2024-12-12
  • Java服務(wù)器處理圖片上傳的方法

    Java服務(wù)器處理圖片上傳的方法

    這篇文章主要為大家詳細(xì)介紹了Java服務(wù)器處理圖片上傳,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06

最新評(píng)論

沙坪坝区| 清丰县| 玛纳斯县| 长汀县| 巴东县| 碌曲县| 林州市| 衡东县| 饶平县| 纳雍县| 许昌市| 射阳县| 新和县| 陕西省| 米易县| 乐业县| 宁晋县| 金门县| 淳化县| 本溪市| 湘潭市| 文山县| 濮阳市| 哈巴河县| 海阳市| 平罗县| 沿河| 仙桃市| 司法| 余江县| 广平县| 潜江市| 库尔勒市| 泗阳县| 昌吉市| 互助| 屯门区| 道孚县| 襄城县| 滕州市| 隆林|