diff --git a/app/src/main/java/jp/atled/agileworks/model/SessionRepository.kt b/app/src/main/java/jp/atled/agileworks/model/SessionRepository.kt index 61092c17729caea6f07cdddf3f137eda5f97dffb..eec33d59d556f296714f068e22c75f1b7c7601d1 100644 --- a/app/src/main/java/jp/atled/agileworks/model/SessionRepository.kt +++ b/app/src/main/java/jp/atled/agileworks/model/SessionRepository.kt @@ -1,16 +1,64 @@ package jp.atled.agileworks.model import android.app.Activity -import jp.atled.agileworks.model.api.ApiCallbackCommon +import android.content.Context +import android.webkit.CookieManager +import jp.atled.agileworks.AwApp +import jp.atled.agileworks.model.api.SessionApiCallback import jp.atled.agileworks.model.api.ApiClient class SessionRepository(private val activity: Activity?) { - fun getSession(onResult: (isSuccess: Boolean, response: SessionResponse?) -> Unit) { + fun getSession(onResult: (isSuccess: Boolean, response: SessionResponse?, headers: Map>?) -> Unit) { val instance = ApiClient.instance(null) - instance.getSession().enqueue(ApiCallbackCommon(activity, onResult)) + instance.getSession().enqueue(SessionApiCallback(activity, onResult)) } companion object { fun getInstance(activity: Activity?) = SessionRepository(activity) + + fun setCookie(setCookieHeaders: List, bodySessionId: String, url: String){ + CookieManager.getInstance().apply { + val preferences = "cookie" + ServerRepository().loadServer().toString() + var cookie = "" + for (header in setCookieHeaders) { + cookie += header + ";" + } + // ヘッダからJSESSIONIDを取得 + val headerSessionId = extractJSessionId(cookie) + + // レスポンスヘッダとボディのJSESSIONIDが同じとき、そのユーザの最新のセッションになる + if(bodySessionId == headerSessionId) { + for (header in setCookieHeaders) { + // Cookieをセット + setCookie(url, header) + } + flush() + // Cookieを保存 + AwApp.instance.applicationContext.getSharedPreferences( + preferences, + Context.MODE_PRIVATE + ) + .edit() + .putString("cookie", cookie) + .apply() + } + } + } + + fun extractJSessionId(cookie: String): String? { + val startIndex = cookie.indexOf("JSESSIONID=") + if (startIndex != -1) { + val jsessionIdPart = cookie.substring(startIndex) + val parts = jsessionIdPart.split(";") + if (parts.isNotEmpty()) { + val jsessionIdValuePair = parts[0] + val valueParts = jsessionIdValuePair.split("=",) + if (valueParts.size == 2) { + return valueParts[1] + } + } + } + return null + } } } \ No newline at end of file diff --git a/app/src/main/java/jp/atled/agileworks/model/api/ApiClient.kt b/app/src/main/java/jp/atled/agileworks/model/api/ApiClient.kt index 068b008114c4caf13d925d023b40642eab5dacf3..e7247c0e94a3708cba36d643c12f60e8377dc30a 100644 --- a/app/src/main/java/jp/atled/agileworks/model/api/ApiClient.kt +++ b/app/src/main/java/jp/atled/agileworks/model/api/ApiClient.kt @@ -153,12 +153,12 @@ object ApiClient { // 保存しているセッションIDを取得 var preferences = "cookie" + ServerRepository().loadServer().toString() val cookiePref = AwApp.instance.applicationContext.getSharedPreferences(preferences, Context.MODE_PRIVATE) - val sessionId = cookiePref.getString("sessionId", "") ?: "" + val cookie = cookiePref.getString("cookie", "") ?: "" interceptor = Interceptor { chain -> val original = chain.request() val requestBuilder = original.newBuilder() val request = requestBuilder - .addHeader("Cookie", "JSESSIONID=$sessionId") + .addHeader("Cookie", cookie) .build() chain.proceed(request) } diff --git a/app/src/main/java/jp/atled/agileworks/model/api/SessionApiCallback.kt b/app/src/main/java/jp/atled/agileworks/model/api/SessionApiCallback.kt new file mode 100644 index 0000000000000000000000000000000000000000..d8a54bbf95ed966a3d32ce4ffb38c50ca1dc5661 --- /dev/null +++ b/app/src/main/java/jp/atled/agileworks/model/api/SessionApiCallback.kt @@ -0,0 +1,50 @@ +package jp.atled.agileworks.model.api + +import android.app.Activity +import android.app.AlertDialog +import android.util.Log +import jp.atled.agileworks.R +import jp.atled.agileworks.view.ui.login.LoginUtil +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class SessionApiCallback( + private val activity: Activity?, + private val onResult: (isSuccess: Boolean, response: T?, headers: Map>?) -> Unit +) : Callback { + + companion object { + private const val TAG = "SessionApiCallback" + } + + override fun onResponse(call: Call, response: Response) { + try { + if (response != null && response.isSuccessful) { + val headers = response.headers().toMultimap() + onResult(true, response.body(), headers) + } else { + onResult(false, null, null) + } + } catch (e: IllegalStateException) { + // 非同期処理が画面遷移後に完了したときに発生する。握りつぶす。 + Log.w(TAG, "IllegalStateException", e) + } + } + + override fun onFailure(call: Call, t: Throwable) { + if ((activity != null) && (t is BadRefreshTokenException)) { + AlertDialog.Builder(activity) + .setTitle(R.string.refresh_token_failure_dialog_title) + .setMessage(R.string.refresh_token_failure_dialog_message) + .setIcon(android.R.drawable.ic_dialog_alert) + .setPositiveButton(R.string.refresh_token_failure_dialog_button_label) { _, _ -> + LoginUtil.reauth(activity) + } + .setCancelable(false) + .show() + } else { + onResult(false, null, null) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/jp/atled/agileworks/view/ui/DrawerMenu.kt b/app/src/main/java/jp/atled/agileworks/view/ui/DrawerMenu.kt index 60c53b5c987a4ca5580aef7a41530c348b551451..166955a317c648283cd559197d017fc89b23de4a 100644 --- a/app/src/main/java/jp/atled/agileworks/view/ui/DrawerMenu.kt +++ b/app/src/main/java/jp/atled/agileworks/view/ui/DrawerMenu.kt @@ -62,7 +62,7 @@ class DrawerMenu { } private fun setupUserName(activity: Activity, drawer: NavigationView) { - SessionRepository.getInstance(activity).getSession { _, response -> + SessionRepository.getInstance(activity).getSession { _, response, _ -> val userName = response?.user?.name.orEmpty() var systemName = response?.system_name.orEmpty() val header = drawer.getHeaderView(0) @@ -75,7 +75,7 @@ class DrawerMenu { private fun showProfile(activity: AppCompatActivity) { // ログイン中に変化があるかもしれないのでメニューが呼ばれる度に取得し直す。 - SessionRepository.getInstance(activity).getSession { _, response -> + SessionRepository.getInstance(activity).getSession { _, response, _ -> val userCode = response?.user?.code.orEmpty() val userName = response?.user?.name.orEmpty() val loginId = response?.user?.loginId.orEmpty() diff --git a/app/src/main/java/jp/atled/agileworks/view/ui/documentweb/DocumentWebFragment.kt b/app/src/main/java/jp/atled/agileworks/view/ui/documentweb/DocumentWebFragment.kt index 9e27c64515eb36d85f44ea6884a262355f225107..f516c95814edccd9866785bdd55f841a124d223e 100644 --- a/app/src/main/java/jp/atled/agileworks/view/ui/documentweb/DocumentWebFragment.kt +++ b/app/src/main/java/jp/atled/agileworks/view/ui/documentweb/DocumentWebFragment.kt @@ -566,27 +566,15 @@ class DocumentWebFragment : Fragment(), DocumentWebPresenter { activity = null } - SessionRepository.getInstance(activity).getSession() { isSuccess, response -> + SessionRepository.getInstance(activity).getSession() { isSuccess, response, headers -> if (isSuccess) { url?.let { url -> val uri = Uri.parse(url) response!!.session_id?.apply { sessionId = response!!.session_id - setCookie( - "https://${uri.host}", - "JSESSIONID=${sessionId}; Path=/${LoginRepository().loadServerContext()}; HttpOnly;Secure;SameSite=None" - ) - flush() - - // セッションID保存 - var preferences = "cookie" + ServerRepository().loadServer().toString() - AwApp.instance.applicationContext.getSharedPreferences( - preferences, - Context.MODE_PRIVATE - ) - .edit() - .putString("sessionId", sessionId) - .apply() + headers?.get("set-cookie")?.also { setCookieHeaders -> + SessionRepository.setCookie(setCookieHeaders, sessionId!!, "https://${uri.host}") + } } if (updateLanguage) { // 多言語対応 diff --git a/app/src/main/java/jp/atled/agileworks/view/ui/login/LoginFragment.kt b/app/src/main/java/jp/atled/agileworks/view/ui/login/LoginFragment.kt index 35e82d774fe755a71bbcfa962ddc329b5b37caba..13a77d7cbf1f7d96f14da6d1fc5bdbdcef0dd688 100644 --- a/app/src/main/java/jp/atled/agileworks/view/ui/login/LoginFragment.kt +++ b/app/src/main/java/jp/atled/agileworks/view/ui/login/LoginFragment.kt @@ -477,7 +477,7 @@ class LoginFragment: Fragment() { if (deviceId != null) { // レスポンスが返ってきたらMainActivity起動 ServerRepository().addServerList() - whenAuthorizationSucceeds() + setCookie() } else { LoginUtil.clearAuthStateAndNotificationToken{ requireActivity().runOnUiThread { @@ -550,15 +550,9 @@ class LoginFragment: Fragment() { val response = ApiClient.instance.getSession().execute() if (response.isSuccessful) { response.body()!!.session_id?.apply { + val setCookieHeaders = response.headers().values("Set-Cookie") val sessionId = response.body()!!.session_id - setCookie("https://${LoginRepository().loadServerUrl()}", "JSESSIONID=${sessionId}; Path=/${LoginRepository().loadServerContext()}; HttpOnly;Secure;SameSite=None") - flush() - // セッションID保存 - var preferences = "cookie" + ServerRepository().loadServer().toString() - AwApp.instance.applicationContext.getSharedPreferences(preferences, Context.MODE_PRIVATE) - .edit() - .putString("sessionId", sessionId) - .apply() + SessionRepository.setCookie(setCookieHeaders, sessionId, "https://${LoginRepository().loadServerUrl()}") } //トークン更新に成功するとメイン画面へ whenAuthorizationSucceeds()