android 会话期
I ended up having to build my library
我最终不得不建立我的图书馆
Over the last 3 months, I have been working on 3 Android apps in parallel. I have to admit, that does take a toll on you. However, you also begin to recognize patterns and redundancies. One of those patterns was around user session management.
在过去的三个月中,我一直在并行开发3个Android应用程序。 我必须承认,这确实给您造成了损失。 但是,您也开始认识到模式和冗余。 这些模式之一是围绕用户会话管理的。
Let’s begin with a simple understanding of what session management is without going too much into the technical detail. Typically, the term session management is used to refer to a process of preserving certain system values or states as long as some conditions hold. An example of common states we like to maintain is those of authenticated user identities.
让我们先简单地了解什么是会话管理,而无需过多地讨论技术细节。 通常,术语“会话管理”用于表示只要某些条件成立,保留某些系统值或状态的过程。 我们希望维护的常见状态的一个示例是经过身份验证的用户身份。
Android provides several ways of doing this but a common methodology is the use of SharedPreferences, which provide a simplified way of storing and retrieving primitive data types in the form of key-value pairs. There are other ways like AccountManagers, but to be honest, that’s an overkill if you are working on a simple application.
Android提供了几种方法来实现此目的,但是一种常用的方法是使用SharedPreferences,它提供了一种简化的方法,以键-值对的形式存储和检索原始数据类型。 还有其他类似AccountManagers的方法,但是老实说,如果您正在开发一个简单的应用程序,那就太过分了。
那么典型的会话到底涉及什么呢? (So what exactly is involved in a typical session?)
When a user enters valid credentials (phone number with OTP combination, username/email and password combination, etc), the typical process is something along these lines:
当用户输入有效的凭证( 带有OTP组合的电话号码,用户名/电子邮件和密码组合等 )时,典型过程如下:
- Credentials are authenticated by the server 凭证由服务器验证
- The server sends back response 服务器发回响应
- The response contains an access token, a refresh token, and an expiry time (usually in seconds) 响应包含访问令牌,刷新令牌和到期时间(通常以秒为单位)
Once you receive this response, maintaining a session would be something like:
收到此回复后,维护会话将类似于:
- Store the token, access token and expiry time 存储令牌,访问令牌和到期时间
- Keep track of the actual expiry date by adding the time the user logged in and the time it takes for the token to expiry 通过添加用户登录时间和令牌到期所需的时间来跟踪实际的到期日期
- When the user comes back to the application, check to see the token has expired based on the time they come back and the time the token was supposed to expire 当用户返回到应用程序时,请根据用户返回的时间和令牌应过期的时间来检查令牌是否已过期
- If the token is expired, make a call to the server with the refresh token to get the new access token 如果令牌已过期,请使用刷新令牌调用服务器以获取新的访问令牌
- Replace the access token, refresh token and expiry time 替换访问令牌,刷新令牌和到期时间
- Repeat 重复
Now for one application, this is fine. Build a simple utility function that does all that and voilà, you are done. However, notice how redundant this starts to become when working with multiple separate apps?
现在对于一个应用程序,这很好。 构建一个简单的实用程序函数即可完成所有工作,您已经完成了。 但是,请注意,在使用多个单独的应用程序时,这种冗余开始变得多么多余?
I looked for an existing library that does what I wanted it to do. I found a couple although they are not maintained and seem deprecated.
我寻找了一个现有的图书馆,可以满足我的要求。 我找到了几对,尽管它们没有维护并且似乎已弃用。
In the spirit of the DRY principle, I decided to package this utility function into a class and export it as a library.
本着DRY原则的精神,我决定将此实用程序功能打包到一个类中,并将其导出为库。
它有什么作用? (What does it do?)
The library abstracts what we just mentioned and all that remains is simple calls to various methods.
该库将我们刚才提到的内容抽象化,剩下的只是对各种方法的简单调用。
Let’s have a look at our starting point. I first decided to employ the use of a Singleton pattern. I did this to ensure a global access point and a single instance of the object I wanted to use. Luckily, Kotlin makes this super simple
让我们看看我们的起点。 我首先决定采用Singleton模式。 我这样做是为了确保要使用的对象具有全局访问点和单个实例。 幸运的是,Kotlin让这个超级简单
Singleton object we shall be working with
我们将使用的单件对象
object SessionManagerUtil {
}
The next step is to define the stub for the methods we will need
下一步是为我们需要的方法定义存根
On a very basic level, we would like to:
在最基本的水平上,我们希望:
- Start a session 开始会议
- Check if the current session is active 检查当前会话是否处于活动状态
- End the session if we need to 如果我们需要结束会议
object SessionManagerUtil {
fun startUserSession() {
}
fun isSessionActive() {
}
fun endUserSession() {
}
}
1.开始用户会话 (1. Starting a user session)
As discussed above, a user session would be started once we have retrieved a response back from the server with the access token, refresh token and expiry time. Ergo, for one to start a user session, we would need to:
如上所述,一旦我们从服务器获取了包含访问令牌,刷新令牌和到期时间的响应,便将开始用户会话。 如此,要启动一个用户会话,我们需要:
- store the access token 存储访问令牌
- store the expiry time = time user logged in + time it takes for the token to expire 存储到期时间=用户登录时间+令牌到期所需的时间
We shall be making use of the SharedPreference. Thus, we also need context.
我们将使用SharedPreference。 因此,我们还需要上下文。
Let’s refactor the method for starting the session to reflect this:
让我们重构启动会话的方法以反映这一点:
// rest hidden for brevity
private const val SESSION_PREFERENCES = "ke.co.skylinedesign.session_manager.SESSION_PREFERENCES"
private const val SESSION_EXPIRY_TIME = "ke.co.skylinedesign.session_manager.SESSION_EXPIRY_TIME"
fun startUserSession(context: Context, expiresIn: Int) {
val calendar = Calendar.getInstance()
val userLoggedInTime = calendar.time
calendar.time = userLoggedInTime
calendar.add(Calendar.SECOND, expiresIn)
val expiryTime = calendar.time
val editor = context.getSharedPreferences(SESSION_PREFERENCES, 0).edit()
editor.putLong(SESSION_EXPIRY_TIME, expiryTime.time)
editor.apply()
}
// rest hidden for brevity
2.检查会话是否处于活动状态 (2. Checking if the session is active)
// code above hidden for brevity
fun isSessionActive(currentTime: Date,context: Context) : Boolean {
val sessionExpiresAt = Date(getExpiryDateFromPreferences(context)!!)
return !currentTime.after(sessionExpiresAt)
}
private fun getExpiryDateFromPreferences(context: Context) : Long? {
return context.getSharedPreferences(SESSION_PREFERENCES, 0).getLong(SESSION_EXPIRY_TIME, 0)
}
// code below hidden for brevity
The next step is for us to update the method to check if the current session is still active or should be ended.
下一步是我们更新方法,以检查当前会话是否仍处于活动状态或应该结束。
For us to check that the current session is active, we need to know it’s being checked against what time. That’s the argument we pass as “currentTime”
为了让我们检查当前会话是否处于活动状态,我们需要知道正在检查几点时间。 这就是我们作为“ currentTime”传递的参数
3.结束会议 (3. End session)
Finally, we need to end the session. This involves clearing out all data from the SharedPreference.
最后,我们需要结束会议。 这涉及从SharedPreference中清除所有数据。
// code above hidden
fun endUserSession(context: Context) {
clearStoredData(context)
}
private fun clearStoredData(context: Context) {
val editor = context.getSharedPreferences(SESSION_PREFERENCES, 0).edit()
editor.clear()
editor.apply()
}
// code below hidden
使用库的示例案例 (An example case of using the library)
An example case of using the library on an Activity to start a session and to check if the current session as below:
使用Activity上的库启动会话并检查当前会话是否为以下示例:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val currentTime = Calendar.getInstance().time
val sessionIsActive = SessionManagerUtil.isSessionActive(currentTime, this)
if (sessionIsActive) startActivity(Intent(this, DashboardActivity::class.java)) // if session is active, push to different activity
button.setOnClickListener {
SessionManagerUtil.startUserSession(this, 60) // starting session
SessionManagerUtil.storeUserToken(this, "randomUserToken") // storing the user token to be used somewhere else
startActivity(Intent(this, DashboardActivity::class.java))
}
}
}
结论 (Conclusion)
I’d love to hear from you guys on how you handle sessions. I’ll be working to refactor the library so that you only start the session once, and checking if the session is active is done as a background task such that there’s no need to keep on calling the method for checking session.
我很想听听你们如何处理会议。 我将努力重构该库,以便您只启动一次会话,并且将检查会话是否处于活动状态作为后台任务完成,从而无需继续调用用于检查会话的方法。
Suggestions are also highly appreciated
建议也受到高度赞赏
The library can be found on GitHub — https://github.com/HenryKenya/session-manager-android
该库可以在GitHub上找到— https://github.com/HenryKenya/session-manager-android
翻译自: https://levelup.gitconnected.com/managing-user-sessions-in-android-360fbf2822
android 会话期