自动登录模块

This commit is contained in:
筱锋xiao_lfeng 2023-11-30 20:07:10 +08:00
parent 0106db1e3b
commit dd5f0452a5
Signed by: XiaoLFeng
GPG Key ID: 6915780EF07491E5
11 changed files with 345 additions and 9 deletions

9
config.json Normal file
View File

@ -0,0 +1,9 @@
{
"mysql": {
"host": "192.168.5.190",
"port": 3306,
"database": "dormstar",
"username": "dormstar",
"password": "114477225588"
}
}

View File

@ -5,4 +5,6 @@ TRUNCATE ds_info;
INSERT INTO ds_info (value, data, commit) VALUES
('title', '201京海市保护伞', '网站标题'),
('sub_title', '我们的宿舍', '网站副标题'),
('register', true, '是否允许注册');
('register', true, '是否允许注册'),
('autoLogin', true, '是否允许自动登录'),
('schoolLoginAddress', 'http://10.1.99.100:801/', '校园登录IP地址')

View File

@ -2,6 +2,11 @@ package com.xlf.dromstarkotlin.cache
object CacheData {
val tokenVisits = HashMap<String, CacheToken>()
var autoLogin = false
var allowRegister = false
const val LOGIN_METHOD = "/eportal/portal/login?callback=dr1003&login_method=1&lang=zh-cn&v=5836"
const val LOGOUT_METHOD = "/eportal/portal/mac/unbind?callback=dr1002&lang=zh"
const val STATUS_METHOD = "/drcom/chkstatus?callback=dr1002"
}
data class CacheToken(

View File

@ -0,0 +1,18 @@
package com.xlf.dromstarkotlin.config
import com.xlf.dromstarkotlin.cache.CacheData
import com.xlf.dromstarkotlin.mapper.InfoMapper
import org.springframework.boot.ApplicationArguments
import org.springframework.boot.ApplicationRunner
import org.springframework.stereotype.Component
@Component
class InitialConfiguration(
val infoMapper: InfoMapper
): ApplicationRunner{
override fun run(args: ApplicationArguments?) {
CacheData.autoLogin = infoMapper.autoLogin()
CacheData.allowRegister = infoMapper.getRegister()
}
}

View File

@ -0,0 +1,61 @@
package com.xlf.dromstarkotlin.config
import com.google.gson.Gson
import com.xlf.dromstarkotlin.entity.voData.ConfigVO
import com.xlf.dromstarkotlin.entity.voData.MysqlVO
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import org.apache.ibatis.session.SqlSessionFactory
import org.mybatis.spring.SqlSessionFactoryBean
import org.mybatis.spring.SqlSessionTemplate
import org.mybatis.spring.annotation.MapperScan
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.io.File
import javax.sql.DataSource
@Configuration
@MapperScan("com.xlf.dromstarkotlin.mapper")
class MysqlConfiguration {
@Bean
@Throws(Exception::class)
fun sqlSessionFactory(dataSource: DataSource?, applicationContext: ApplicationContext?): SqlSessionFactory? {
val factoryBean = SqlSessionFactoryBean()
factoryBean.setDataSource(dataSource)
// 配置其他属性如mapper位置等
return factoryBean.getObject()
}
@Bean
@Throws(Exception::class)
fun sqlSessionTemplate(sqlSessionFactory: SqlSessionFactory?): SqlSessionTemplate {
return SqlSessionTemplate(sqlSessionFactory)
}
@Bean
fun dataSource(): DataSource {
// 获取json配置文件中的数据库配置
val gson = Gson()
// 读取配置文件 config.json
val getConfig: String = if (File("./config.json").exists()) {
File("./config.json").readText(Charsets.UTF_8)
} else {
File("./config.json").createNewFile()
// 输入信息进入文件
File("./config.json").writeText(gson.toJson(ConfigVO(MysqlVO("127.0.0.1", 3306, "root", "123456", "dromstar"))))
File("./config.json").readText(Charsets.UTF_8)
}
val configVO = gson.fromJson(getConfig, ConfigVO::class.java).mysql
// 数据库链接
val hikariConfig = HikariConfig()
hikariConfig.driverClassName = "com.mysql.cj.jdbc.Driver"
hikariConfig.jdbcUrl = "jdbc:mysql://${configVO.host}:${configVO.port}/${configVO.database}"
hikariConfig.username = configVO.username
hikariConfig.password = configVO.password
return HikariDataSource(hikariConfig)
}
}

View File

@ -0,0 +1,32 @@
package com.xlf.dromstarkotlin.controllers
import com.frontleaves.general.utils.BaseResponse
import com.frontleaves.general.utils.ResultUtil
import com.xlf.dromstarkotlin.services.AccountService
import jakarta.servlet.http.HttpServletRequest
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.util.regex.Pattern
@RestController
@RequestMapping("/api/account")
class AccountController(
val accountService: AccountService
) {
@GetMapping("/info")
fun getInfo(httpServletRequest: HttpServletRequest): ResponseEntity<BaseResponse> {
val hashMap = HashMap<String, Any?>()
val getMap = accountService.getInformation()
val matcherUid = Pattern.compile("^[0-9]+").matcher(getMap?.get("uid").toString())
.also { it.find() }
val matcherType = Pattern.compile("[a-z]+$").matcher(getMap?.get("uid").toString())
.also { it.find() }
hashMap["ip"] = getMap?.get("v46ip")
hashMap["time"] = getMap?.get("time")
hashMap["uid"] = matcherUid.group(0)
hashMap["type"] = matcherType.group(0)
return ResultUtil.success(hashMap, httpServletRequest)
}
}

View File

@ -1,8 +1,15 @@
package com.xlf.dromstarkotlin.mapper
import com.xlf.dromstarkotlin.entity.doData.AccountDO
import org.apache.ibatis.annotations.Mapper
import org.apache.ibatis.annotations.Select
@Mapper
interface AccountMapper {
@Select("SELECT COUNT(*) FROM ds_account")
fun getCountAccount(): Int
@Select("SELECT * FROM ds_account WHERE id = #{nextInt}")
fun getAccountById(nextInt: Int): AccountDO
}

View File

@ -6,6 +6,12 @@ import org.apache.ibatis.annotations.Select
@Mapper
interface InfoMapper {
@Select("SELECT * FROM dormstar.ds_info WHERE value = 'register'")
@Select("SELECT * FROM ds_info WHERE value = 'register'")
fun getRegister(): Boolean
@Select("SELECT * FROM ds_info WHERE value = 'schoolLoginAddress'")
fun getSchoolLoginIpAddress(): String
@Select("SELECT * FROM ds_info WHERE value = 'autoLogin'")
fun autoLogin(): Boolean
}

View File

@ -0,0 +1,152 @@
package com.xlf.dromstarkotlin.services
import com.google.gson.Gson
import com.xlf.dromstarkotlin.cache.CacheData
import com.xlf.dromstarkotlin.entity.doData.AccountDO
import com.xlf.dromstarkotlin.mapper.AccountMapper
import okhttp3.OkHttpClient
import okhttp3.Request
import org.springframework.stereotype.Service
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
import java.util.regex.Pattern
import kotlin.collections.HashMap
@Service
class AccountService(
val accountMapper: AccountMapper
) {
// 进行 okHttp 配置
val okHttpClient = OkHttpClient()
fun checkWhetherYouAreLoggedIn(): Boolean {
// 获取百度网站
val request = Request.Builder()
.url("https://www.baidu.com")
.build()
try {
val response = okHttpClient.newCall(request).execute()
return if (response.code == 200) {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <200>CheckWhetherYouAreLoggedInSuccess")
true
} else {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <${response.code}>CheckWhetherYouAreLoggedInFailed")
false
}
} catch (e: IOException) {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <500>CheckWhetherYouAreLoggedInFailed | ${e.message}")
}
return false
}
fun regularLogin() {
// 获取登录地址
val getAccountDO = randomAccount()
val getLink = "http://10.1.99.100:801${CacheData.LOGIN_METHOD}&user_account=,0,${getAccountDO.user}@${getAccountDO.type}&user_password=${getAccountDO.password}"
val request = Request.Builder()
.url(getLink)
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0")
.build()
try {
val response = okHttpClient.newCall(request).execute()
val matcher = Pattern.compile("dr1003\\(([^)]+)\\)").matcher(response.body!!.string())
matcher.find()
val getResponseBody = Gson().fromJson(matcher.group(1), HashMap::class.java)
if (getResponseBody["result"] == "1") {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <200>AutoLoginSuccess | Message:${getResponseBody["msg"]}")
} else if (getResponseBody["result"] == "0") {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <200>AutoLoginAccountDoesNotExist | Message:${getResponseBody["msg"]}")
} else {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <200>AutoLoginUnknownError | Message:${getResponseBody["msg"]}")
}
} catch (e: IOException) {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <500>AutoLoginFailed | ${e.message}")
}
}
fun regularLogout() {
// 获取信息
val requestInfo = Request.Builder()
.url("http://localhost:8080/api/account/info")
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0")
.build()
try {
val response = okHttpClient.newCall(requestInfo).execute()
val getResponseBody = Gson().fromJson(response.body!!.string(), HashMap::class.java)
.also { Gson().fromJson(it["data"].toString(), HashMap::class.java) }
// 获取登出地址
val getLink = "http://10.1.99.100:801${CacheData.LOGOUT_METHOD}&user_account=${getResponseBody["uid"]}"
val request = Request.Builder()
.url(getLink)
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)")
.build()
try {
val response = okHttpClient.newCall(request).execute()
val matcher = Pattern.compile("dr1003\\(([^)]+)\\)").matcher(response.body!!.string())
matcher.find()
val getResponseBody = Gson().fromJson(matcher.group(1), HashMap::class.java)
if (getResponseBody["result"] == "1") {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <200>AutoLogoutSuccess | Message:${getResponseBody["msg"]}")
} else if (getResponseBody["result"] == "0") {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <200>AutoLogoutAccountDoesNotExist | Message:${getResponseBody["msg"]}")
} else {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <200>AutoLogoutUnknownError | Message:$getResponseBody")
}
} catch (e: IOException) {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <500>AutoLogoutFailed | ${e.message}")
}
} catch (e: IOException) {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <500>InternalServiceError | ${e.message}")
}
}
fun getInformation(): HashMap<*, *>? {
// 获取当前信息
val getLink = "http://" + "10.1.99.100" + CacheData.STATUS_METHOD
val request = Request.Builder()
.url(getLink)
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)")
.build()
return try {
val response = okHttpClient.newCall(request).execute()
val matcher = Pattern.compile("dr1002\\(([^)]+)\\)").matcher(response.body!!.string())
matcher.find()
Gson().fromJson(matcher.group(1), HashMap::class.java)
} catch (e: IOException) {
e.printStackTrace()
null
}
}
fun switchTheCampusNetwork() {
// 获取登录地址
val getAccountDO = randomAccount()
val getLink = "http://10.1.99.100:801${CacheData.LOGIN_METHOD}&user_account=,0,${getAccountDO.user}&user_password=${getAccountDO.password}"
val request = Request.Builder()
.url(getLink)
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0")
.build()
try {
val response = okHttpClient.newCall(request).execute()
val matcher = Pattern.compile("dr1003\\(([^)]+)\\)").matcher(response.body!!.string())
matcher.find()
val getResponseBody = Gson().fromJson(matcher.group(1), HashMap::class.java)
if (getResponseBody["result"] == "1") {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <200>AutoLoginSuccess[School] | Message:${getResponseBody["msg"]}")
} else if (getResponseBody["result"] == "0") {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <200>AutoLoginAccountDoesNotExist[School] | Message:${getResponseBody["msg"]}")
} else {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <200>AutoLoginUnknownError[School] | Message:${getResponseBody["msg"]}")
}
} catch (e: IOException) {
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <500>AutoLoginFailed[School] | ${e.message}")
}
}
fun randomAccount(): AccountDO {
// 随机获取用户
val getCount = accountMapper.getCountAccount()
return accountMapper.getAccountById(Random().nextInt(getCount)+1)
}
}

View File

@ -1,5 +1,6 @@
package com.xlf.dromstarkotlin.services
import com.xlf.dromstarkotlin.cache.CacheData
import com.xlf.dromstarkotlin.mapper.TokenMapper
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component
@ -8,9 +9,13 @@ import java.util.*
@Component
class ScheduleService(
val tokenMapper: TokenMapper
val tokenMapper: TokenMapper,
val accountService: AccountService
) {
/**
* 清除过期的 Token
*/
@Scheduled(fixedDelay = 900000)
fun clearExpiredToken() {
// 循环所有 Token 信息
@ -40,4 +45,49 @@ class ScheduleService(
}
println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())} [Log] <----->Scheduled | Message:clear token $i")
}
/**
* 登录校园网5分钟自动检查
*/
@Scheduled(fixedDelay = 300000)
fun schoolLogin() {
if (CacheData.autoLogin) {
val calendar = Calendar.getInstance()
val hour = SimpleDateFormat("HH").format(Date()).toInt()
val minute = SimpleDateFormat("mm").format(Date()).toInt()
// 检查星期
if (calendar.get(Calendar.DAY_OF_WEEK) in 1..5) {
// 允许登录时间范围
if (hour in 7..<23) {
// 登录
if (!accountService.checkWhetherYouAreLoggedIn()) {
accountService.regularLogin()
}
} else {
// 切换校园网
do {
accountService.regularLogout()
Thread.sleep(5000)
} while (accountService.getInformation()?.get("uid") == null)
accountService.switchTheCampusNetwork()
}
} else {
if (hour in 7 .. 23) {
if (hour < 23 || (hour == 23 && minute in 0..30)) {
// 登录
if (!accountService.checkWhetherYouAreLoggedIn()) {
accountService.regularLogin()
}
} else{
// 切换校园网
do {
accountService.regularLogout()
Thread.sleep(5000)
} while (accountService.getInformation()?.get("uid") == null)
accountService.switchTheCampusNetwork()
}
}
}
}
}
}

View File

@ -1,6 +0,0 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.5.190:3306
username: dormstar
password: 114477225588