關(guān)于SpringSecurity?Context?中獲取和更改當(dāng)前用戶(hù)信息的問(wèn)題
SpringSecurity Context 獲取和更改用戶(hù)信息的問(wèn)題
SecurityContext 異步線程中獲取用戶(hù)信息
今天在做項(xiàng)目時(shí)遇到了一個(gè)問(wèn)題,我需要獲取當(dāng)前用戶(hù)的 ID。之前,前端并沒(méi)有存儲(chǔ)用戶(hù)信息,我一直是在后端的 service
中通過(guò) SecurityContext
來(lái)獲取用戶(hù)信息,這個(gè)方法之前一直有效。然而,今天在另一個(gè) service
中調(diào)用時(shí)卻無(wú)法獲取到用戶(hù)信息。
經(jīng)過(guò)詳細(xì)排查,發(fā)現(xiàn) SecurityContext
的內(nèi)容是與請(qǐng)求線程(如 HTTP 請(qǐng)求)綁定的。但我當(dāng)前的 service
是用于處理 MQTT 消息,這屬于異步線程。因此,在異步線程中無(wú)法從 SecurityContext
獲取用戶(hù)信息,只能另尋解決方案。
/** * 處理接收到的設(shè)備數(shù)據(jù),根據(jù)數(shù)據(jù)類(lèi)型進(jìn)行不同的處理。energy數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù),其他數(shù)據(jù)通過(guò)WebSocket發(fā)送到前端展示。 * @param data 數(shù)據(jù)內(nèi)容 */ private void handleIncomingData(String data) { ...... /* * 通過(guò)設(shè)備ID找到用戶(hù)ID, 不能通過(guò)securityContext獲取當(dāng)前用戶(hù)ID,因?yàn)檫@里是異步處理消息,不在請(qǐng)求線程中。 * 通過(guò)securityContext獲取當(dāng)前用戶(hù)ID的方法只能在請(qǐng)求線程中使用,通常是與HTTP請(qǐng)求相關(guān)的操作才能獲取到。 * 這里是MQTT消息處理,不在請(qǐng)求線程中,所以要通過(guò)其他方式獲取當(dāng)前用戶(hù)ID。 * 還因?yàn)檫@里是存入數(shù)據(jù)庫(kù),因?yàn)橐膊荒芤蕾?lài)物理設(shè)備的用戶(hù)ID,設(shè)備不一定是存用戶(hù)ID, 降低耦合性。 TODO: 這里是否可以改進(jìn)? */ long userId = deviceMapper.findDeviceById(deviceId).getUserId(); if (userId<=0) {//如果userId<=0,說(shuō)明沒(méi)有找到對(duì)應(yīng)的設(shè)備 logger.error("Failed to get user id by device id: {}", deviceId); throw new RuntimeException("Failed to get user id by device id: " + deviceId); } Energy energy = new Energy(); energy.setDeviceId(deviceId); energy.setEnergy(totalEnergy); energy.setRecordDate(recordDate); energy.setUserId(userId); ...... }
SecurityContext 線程降級(jí)問(wèn)題
在項(xiàng)目中遇到 SecurityContext
線程降級(jí)的問(wèn)題,具體場(chǎng)景是用戶(hù)修改個(gè)人資料(如郵箱)后,我希望 SecurityContext
中的用戶(hù)信息能及時(shí)更新。然而,在修改郵箱后,用戶(hù)需要跳轉(zhuǎn)到郵箱驗(yàn)證碼驗(yàn)證頁(yè)面,該頁(yè)面通過(guò) security
配置中的 permitAll()
允許匿名訪問(wèn)。
這個(gè)配置導(dǎo)致一個(gè)問(wèn)題:雖然用戶(hù)已經(jīng)登錄認(rèn)證,但在訪問(wèn) /verify-code
頁(yè)面時(shí),SecurityContext
中的身份會(huì)被降級(jí)為匿名用戶(hù),進(jìn)而導(dǎo)致更新后的信息沒(méi)有在 SecurityContext
中及時(shí)反映。
我了解到可以通過(guò) setAuthentication()
手動(dòng)更新 SecurityContext
,但嘗試后依然無(wú)法解決問(wèn)題,更新后的用戶(hù)信息仍舊無(wú)法及時(shí)同步到 SecurityContext
中~
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(AbstractHttpConfigurer::disable) // disable csrf .authorizeHttpRequests(authorize -> authorize .requestMatchers("/login","/register","/verify-code","/forgot-password","/change-password").permitAll()// permit request without authentication .requestMatchers("/ws/**").permitAll()// permit websocket request without authentication .anyRequest().authenticated() ) .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class) .logout(AbstractHttpConfigurer::disable);// disable logout otherwise it will conflict with our custom logout return http.build(); }
到此這篇關(guān)于SpringSecurity Context 中 獲取 和 更改 當(dāng)前用戶(hù)信息的問(wèn)題的文章就介紹到這了,更多相關(guān)SpringSecurity Context 獲取當(dāng)前用戶(hù)信息內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Synchronized和ReentranLock的區(qū)別及說(shuō)明
文章介紹了Java中的`synchronized`關(guān)鍵字和`ReentrantLock`類(lèi),兩者都可以用于解決多線程同步問(wèn)題,但`ReentrantLock`提供了更多的功能和靈活性2024-12-12jmeter調(diào)試錯(cuò)誤全集(入門(mén)必備)
在使用jmeter做接口測(cè)試的過(guò)程中大家是不是經(jīng)常會(huì)遇到很多問(wèn)題,本文就介紹了jmeter調(diào)試錯(cuò)誤全集,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11使用Lombok @Builder注解導(dǎo)致默認(rèn)值無(wú)效的問(wèn)題
這篇文章主要介紹了使用Lombok @Builder注解導(dǎo)致默認(rèn)值無(wú)效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08java使用監(jiān)聽(tīng)器實(shí)現(xiàn)一個(gè)統(tǒng)計(jì)網(wǎng)站在線人數(shù)的示例
本文主要介紹了java使用監(jiān)聽(tīng)器實(shí)現(xiàn)一個(gè)統(tǒng)計(jì)網(wǎng)站在線人數(shù)的示例,具有一定的參考價(jià)值,有需要的朋友可以了解一下。2016-10-10Java Annotation注解相關(guān)原理代碼總結(jié)
這篇文章主要介紹了Java Annotation注解相關(guān)原理代碼總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07javascript與jsp發(fā)送請(qǐng)求到servlet的幾種方式實(shí)例
本文分別給出了javascript發(fā)送請(qǐng)求到servlet的5種方式實(shí)例與 jsp發(fā)送請(qǐng)求到servlet的6種方式實(shí)例2018-03-03