security(chat): secure chat stream endpoint with jwt validation and token extraction

This commit is contained in:
844143714@qq,com 2026-05-19 22:24:29 +08:00
parent 05392384b6
commit 6d12291941
4 changed files with 18 additions and 4 deletions

View File

@ -10,6 +10,7 @@ object AppConfig {
private const val KEY_REMEMBER_LOGIN = "remember_login"
private const val KEY_USERNAME = "saved_username"
private const val KEY_PASSWORD = "saved_password"
private const val KEY_ACCESS_TOKEN = "access_token"
// 默认配置
const val DEFAULT_SERVER_URL = "https://template.gyouzhe.com"
@ -68,4 +69,12 @@ object AppConfig {
fun setSavedPassword(context: Context, password: String) {
getPrefs(context).edit().putString(KEY_PASSWORD, password).apply()
}
fun getAccessToken(context: Context): String {
return getPrefs(context).getString(KEY_ACCESS_TOKEN, "") ?: ""
}
fun setAccessToken(context: Context, token: String) {
getPrefs(context).edit().putString(KEY_ACCESS_TOKEN, token).apply()
}
}

View File

@ -155,6 +155,7 @@ class LoginActivity : AppCompatActivity() {
val data = json.optJSONObject("data")
val loginData = data?.toString() ?: "{}"
val accessToken = data?.optString("access_token", "") ?: ""
AppConfig.setAccessToken(this@LoginActivity, accessToken)
Toast.makeText(applicationContext, "登录成功", Toast.LENGTH_SHORT).show()

View File

@ -1,7 +1,9 @@
package com.stand.standapp.ui.chat
import androidx.lifecycle.ViewModel
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.stand.standapp.AppConfig
import com.stand.standapp.ui.chat.model.ChatMessage
import com.stand.standapp.ui.chat.model.ChatSession
import com.stand.standapp.ui.chat.repo.AiChatRepository
@ -13,7 +15,7 @@ import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.launch
import java.util.UUID
class ChatViewModel : ViewModel() {
class ChatViewModel(application: Application) : AndroidViewModel(application) {
private val repository = AiChatRepository()
private val _sessions = MutableStateFlow<List<ChatSession>>(emptyList())
@ -56,7 +58,8 @@ class ChatViewModel : ViewModel() {
// 4. 发起网络请求,流式追加内容
viewModelScope.launch {
repository.streamChat(content)
val token = AppConfig.getAccessToken(getApplication())
repository.streamChat(content, token)
.catch { e ->
appendAiMessageChunk(aiMsgId, "\n[请求异常: ${e.message}]")
finalizeAiMessage(aiMsgId)

View File

@ -22,11 +22,12 @@ class AiChatRepository {
.readTimeout(0, TimeUnit.MILLISECONDS) // SSE 需要关闭读取超时
.build()
fun streamChat(message: String): Flow<String> = callbackFlow {
fun streamChat(message: String, token: String): Flow<String> = callbackFlow {
val json = """{"message": "$message"}"""
val request = Request.Builder()
.url(backendUrl)
.post(json.toRequestBody("application/json".toMediaType()))
.header("Authorization", "Bearer $token")
.header("Accept", "text/event-stream")
.build()