Skip to content

Commit

Permalink
feat:auth模块操作记录,并在op系统展示 TencentBlueKing#973
Browse files Browse the repository at this point in the history
  • Loading branch information
lannoy0523 committed Jul 26, 2023
1 parent d030ef7 commit 514caab
Show file tree
Hide file tree
Showing 7 changed files with 320 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ import com.tencent.bkrepo.common.api.constant.MS_AUTH_HEADER_UID
import com.tencent.bkrepo.common.api.constant.PLATFORM_KEY
import com.tencent.bkrepo.common.api.constant.StringPool.COLON
import com.tencent.bkrepo.common.api.constant.USER_KEY
import com.tencent.bkrepo.common.operate.api.OperateLogService
import com.tencent.bkrepo.common.operate.api.pojo.OperateLog
import com.tencent.bkrepo.common.operate.service.util.DesensitizedUtils
import com.tencent.bkrepo.common.security.exception.AuthenticationException
import com.tencent.bkrepo.common.security.exception.PermissionException
import com.tencent.bkrepo.common.security.http.core.HttpAuthSecurity
Expand All @@ -76,8 +79,12 @@ import com.tencent.bkrepo.common.service.util.SpringContextUtils
import com.tencent.bkrepo.repository.constant.SYSTEM_USER
import org.apache.commons.codec.digest.HmacAlgorithms
import org.slf4j.LoggerFactory
import org.springframework.core.DefaultParameterNameDiscoverer
import org.springframework.core.ParameterNameDiscoverer
import org.springframework.web.method.HandlerMethod
import org.springframework.web.servlet.HandlerInterceptor
import org.springframework.web.servlet.HandlerMapping
import java.lang.reflect.Method
import java.util.Base64
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
Expand All @@ -90,6 +97,10 @@ class AuthInterceptor(

private val userService: UserService by lazy { SpringContextUtils.getBean() }

private val operateLogService:OperateLogService by lazy { SpringContextUtils.getBean() }

private val parameterNameDiscoverer: ParameterNameDiscoverer = DefaultParameterNameDiscoverer()

override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
val authHeader = request.getHeader(AUTHORIZATION).orEmpty()
val authFailStr = String.format(AUTH_FAILED_RESPONSE, authHeader)
Expand Down Expand Up @@ -121,6 +132,58 @@ class AuthInterceptor(
}
}

override fun afterCompletion(
request: HttpServletRequest,
response: HttpServletResponse,
handler: Any,
ex: Exception?
) {

val des = getDescription(request, (handler as HandlerMethod).method)
val operateLog = OperateLog(
type = handler.toString(),
projectId = "",
repoName = "",
resourceKey = "",
userId = request.getAttribute(USER_KEY) as? String ?: ANONYMOUS_USER,
clientAddress = request.getRemoteAddr(),
description = getDescription(request, (handler as HandlerMethod).method)
)
operateLogService.save(operateLog)
}

private fun getDescription(request: HttpServletRequest,method: Method):Map<String, Any> {
// 获取url中请求参数
val urlParams:Map<String, Any?> = request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE) as Map<String, Any?>
// 获取方法中的请求参数
val methodParams = request.parameterMap
// 获取方法中的requestBody
val requestBody = StringBuilder()
val reader = request.reader
var line: String?
while (reader.readLine().also { line = it } != null) {
requestBody.append(line)
}
val parameterNames = parameterNameDiscoverer.getParameterNames(method)
val parameters = method.parameters
val argsMap: MutableMap<String, Any?> = LinkedHashMap()
for (i in parameters.indices) {
val parameter = parameters[i]
val parameterName = parameterNames?.get(i) ?: parameter.name
argsMap[parameterName] = if (urlParams.keys.contains(parameterName)) {
urlParams.get(parameterName)
} else if (methodParams.keys.contains(parameterName)) {
methodParams.get(parameterName)
} else if (requestBody.isNullOrEmpty()){
methodParams
} else {
requestBody.toString()
}
}
return argsMap as Map<String, Any>
}


private fun checkUserFromBasic(request: HttpServletRequest, authHeader: String): Boolean {
val projectAccess = userProjectApiSet.any { request.requestURI.contains(it) }
val userAccess = userAccessApiSet.any { request.requestURI.contains(it) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.TimeZone
import java.util.regex.Pattern

/**
* OperateLogService 实现类
Expand Down Expand Up @@ -232,12 +233,13 @@ open class OperateLogServiceImpl(
startTime: String?,
endTime: String?
): Query {
val criteria = if (type != null) {
val criteria = if (type != null && type != "AUTH_LOG") {
Criteria.where(TOperateLog::type.name).`in`(getEventList(type))
} else if (type != null && type == "AUTH_LOG") {
Criteria.where(TOperateLog::type.name).regex(Pattern.compile("^.*com.tencent.bkrepo.auth.*$"))
} else {
Criteria.where(TOperateLog::type.name).nin(nodeEvent)
}

projectId?.let { criteria.and(TOperateLog::projectId.name).`is`(projectId) }

repoName?.let { criteria.and(TOperateLog::repoName.name).`is`(repoName) }
Expand All @@ -249,13 +251,13 @@ open class OperateLogServiceImpl(
val start = sdf.parse(startTime)
start.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
} else {
LocalDateTime.now()
LocalDateTime.now().minusMonths(3L)
}
val localEnd = if (endTime != null && endTime.isNotBlank()) {
val end = sdf.parse(endTime)
end.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
} else {
LocalDateTime.now().minusMonths(3L)
LocalDateTime.now()
}
criteria.and(TOperateLog::createdDate.name).gte(localStart).lte(localEnd)
return Query(criteria).with(Sort.by(TOperateLog::createdDate.name).descending())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* BK-CI 蓝鲸持续集成平台 is licensed under the MIT license.
*
* A copy of the MIT License is included in this file.
*
*
* Terms of the MIT License:
* ---------------------------------------------------
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of
* the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package com.tencent.bkrepo.opdata.controller

import com.tencent.bkrepo.common.api.pojo.Page
import com.tencent.bkrepo.common.api.pojo.Response
import com.tencent.bkrepo.common.operate.api.OperateLogService
import com.tencent.bkrepo.common.operate.api.pojo.OperateLogResponse
import com.tencent.bkrepo.common.service.util.ResponseBuilder
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.ApiParam
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

@Api("auth模块日志接口")
@RestController
@RequestMapping("/api/log")
class AuthOperateLogController(
private val operateLogService: OperateLogService
) {

@ApiOperation("auth日志查询接口")
@GetMapping("/page")
fun page(
@ApiParam("项目名", required = false)
@RequestParam projectId: String?,
@ApiParam("仓库名", required = false)
@RequestParam repoName: String?,
@ApiParam("操作人", required = false)
@RequestParam operator: String?,
@ApiParam("开始时间", required = false)
@RequestParam startTime: String?,
@ApiParam("结束时间", required = false)
@RequestParam endTime: String?,
@ApiParam("页数", required = false, defaultValue = "1")
@RequestParam pageNumber: Int?,
@ApiParam("每页数量", required = false, defaultValue = "20")
@RequestParam pageSize: Int?
): Response<Page<OperateLogResponse?>> {
val page = operateLogService.page(
"AUTH_LOG", projectId, null,
operator, startTime, endTime, pageNumber ?: 1, pageSize ?: 20
)
return ResponseBuilder.success(page)
}
}
19 changes: 19 additions & 0 deletions src/frontend/devops-op/src/api/auth-log.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import request from '@/utils/request'

const PREFIX_SERVICES = '/opdata/api'
export const DEFAULT_PAGE_SIZE = 10

export function page(num, size, projectId, startTime, endTime, userId) {
return request({
url: `${PREFIX_SERVICES}/log/page`,
method: 'get',
params: {
projectId: projectId,
startTime: startTime,
endTime: endTime,
operator: userId,
pageNumber: num,
pageSize: size
}
})
}
1 change: 1 addition & 0 deletions src/frontend/devops-op/src/icons/svg/cc-log.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions src/frontend/devops-op/src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const ROUTER_NAME_PROJECT_SCAN_CONFIGURATIONS = 'ProjectScanConfiguration
export const ROUTER_NAME_FILTER_RULE = 'FilterRule'
export const ROUTER_NAME_JOB = 'Job'
export const ROUTER_NAME_SHED_LOCK = 'Shedlock'
export const ROUTER_NAME_AUTH_LOG = 'AuthLog'

Vue.use(Router)

Expand Down Expand Up @@ -272,6 +273,18 @@ export const asyncRoutes = [
}
]
},
{
path: '/auth-log',
component: Layout,
children: [
{
path: '/',
name: ROUTER_NAME_AUTH_LOG,
meta: { title: 'AUTH模块日志', icon: 'cc-log' },
component: () => import('@/views/auth-log/index')
}
]
},
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true }
]
Expand Down
Loading

0 comments on commit 514caab

Please sign in to comment.