经典 ASP 调用 TekRADIUS 外部 CLI 工具实现账号自助重置
实验环境:
- 网关:RouterOS v7.19.4
- 认证:TekRADIUS v5.7
- 数据:SQL Server 2008 R2 Enterprise
- 系统:Windows Server 2022 Standard + Internet Information Services (IIS)
核心技术栈
- 后端引擎:Classic ASP (VBScript) 在 Windows Server 环境下部署极快。
- Radius 服务器:TekRADIUS(广泛用于拨号上网认证)。
- 数据库:SQL Server ( SQLNCLI10 ) 用于校验账号合法性。
- 执行工具:
trcli.exeTekRADIUS 提供的命令行工具,用于实时修改认证数据。
重置代码 password-reset.asp
<%
Option Explicit
Response.Buffer = True
Response.Charset = "UTF-8"
' -------------------------
' TekRADIUS trcli.exe 路径
' -------------------------
Const TRCLI_PATH = "C:\Program Files\TekRADIUS\trcli.exe"
' -------------------------
' 数据库配置(仅用于检查账号是否存在)
' -------------------------
Dim DB_SERVER, DB_NAME, DB_USER, DB_PASS
DB_SERVER = "1.1.1.1"
DB_NAME = "TekRADIUS"
DB_USER = "sa"
DB_PASS = "111111"
' -------------------------
' 工具函数
' -------------------------
Function TrimSafe(s)
If IsNull(s) Then
TrimSafe = ""
Else
TrimSafe = Trim(CStr(s))
End If
End Function
Sub Fail(msg)
Response.Write "<script>alert('" & Replace(msg,"'","\'") & "');history.back();</script>"
Response.End
End Sub
Function Success(msg)
Response.Write "<script>alert('" & Replace(msg,"'","\'") & "');window.location='password.asp';</script>"
Response.End
End Function
Function RunCmd(cmd)
Dim WshShell, execObj, output
Set WshShell = Server.CreateObject("WScript.Shell")
Set execObj = WshShell.Exec(cmd)
output = execObj.StdOut.ReadAll & vbCrLf & execObj.StdErr.ReadAll
RunCmd = output
End Function
' -------------------------
' 表单提交处理
' -------------------------
If Request.ServerVariables("REQUEST_METHOD") = "POST" Then
Dim username, newpwd, confpwd
username = TrimSafe(Request.Form("username"))
newpwd = TrimSafe(Request.Form("newpwd"))
confpwd = TrimSafe(Request.Form("confpwd"))
If username = "" Or newpwd = "" Or confpwd = "" Then Fail "请填写所有字段!"
If newpwd <> confpwd Then Fail "新的密码与确认密码不一致!"
If Len(newpwd) < 6 Then Fail "密码至少需要 6 位!"
' -------------------------
' 检查账号是否存在
' -------------------------
Dim conn, cmd, rs
Set conn = Server.CreateObject("ADODB.Connection")
conn.Open "Provider=SQLNCLI10;Server=" & DB_SERVER & ";Database=" & DB_NAME & ";Uid=" & DB_USER & ";Pwd=" & DB_PASS & ";"
Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn
cmd.CommandType = 1 ' adCmdText
cmd.CommandText = "SELECT UserName FROM dbo.Users WHERE RTRIM(UserName)=?"
cmd.Parameters.Append cmd.CreateParameter("", 202, 1, 64, username)
Set rs = cmd.Execute()
If rs.EOF Then
rs.Close
conn.Close
Fail "上网账号不存在!"
End If
rs.Close
conn.Close
' -------------------------
' 调用 trcli.exe 修改密码(重置)
' -------------------------
Dim delCmd, addCmd
' 生成可在 cmd 中正确执行的命令(路径空格问题已解决)
delCmd = "%comspec% /c """"" & TRCLI_PATH & """" & " -m " & username & " ""ietf|2"" check"""
RunCmd(delCmd)
addCmd = "%comspec% /c """"" & TRCLI_PATH & """" & " -a " & username & " ""ietf|2"" " & newpwd & " check"""
RunCmd(addCmd)
Success "上网密码重置成功!"
End If
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PPPoE上网账号_密码重置</title>
<style>
body{font-family:Arial, "Microsoft YaHei"; margin:30px;}
.form{max-width:420px; padding:18px; border:1px solid #ddd; border-radius:6px; box-shadow:0 2px 6px rgba(0,0,0,.05);}
.form h2{margin-top:0;}
.form label{display:block; margin:4px 0 2px;}
.form input[type=text], .form input[type=password]{width:100%; padding:8px; box-sizing:border-box;}
.form .btn{margin-top:12px; padding:8px 12px; cursor:pointer;}
</style>
<script>
function validateForm(){
var u=document.getElementById('username').value.trim();
var np=document.getElementById('newpwd').value;
var cp=document.getElementById('confpwd').value;
if(u===''||np===''||cp===''){alert('请填写所有字段!');return false;}
if(np!==cp){alert('新的密码与确认密码不一致!');return false;}
if(np.length<6){alert('密码至少需要 6 位!');return false;}
return true;
}
</script>
</head>
<style>
/* 全局样式 */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
margin: 0;
padding: 20px 0 0 0; /* 页面上方留空,不会贴顶 */
background-color: #f0f2f5;
}
/* 表单容器 */
.form {
width: 90%; /* 移动端:占屏幕 90% */
max-width: 420px; /* 大屏:最大宽度 420px */
margin: 0 auto; /* 关键:水平居中 */
padding: 30px;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
background-color: #ffffff;
box-sizing: border-box;
text-align: left;
}
/* 标题 */
.form h2 {
margin-top: 0;
margin-bottom: 24px;
text-align: center;
color: #333333;
font-size: 22px;
font-weight: 600;
}
/* 标签 */
.form label {
display: block;
margin-bottom: 8px;
color: #555555;
font-weight: 500;
font-size: 14px;
}
/* 输入框 */
.form input[type=text],
.form input[type=password] {
width: 100%;
padding: 12px;
margin-bottom: 14px;
border: 1px solid #dcdfe6;
border-radius: 8px;
box-sizing: border-box;
font-size: 14px;
transition: border-color 0.3s, box-shadow 0.3s;
}
.form input[type=text]:focus,
.form input[type=password]:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
}
/* 按钮 */
/* font-weight: 500; */
/* font-weight: bold; */
.form .btn {
width: 100%;
padding: 12px;
border: none;
border-radius: 8px;
background-color: #409eff;
color: white;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s, transform 0.2s;
}
.form .btn:hover {
background-color: #66b1ff;
}
.form .btn:active {
background-color: #3a8ee6;
transform: translateY(1px);
}
/* 底部帮助区 */
.help-section {
display: flex;
justify-content: space-between;
margin-top: 16px;
font-weight: 500;
font-size: 14px;
}
.help-section a {
color: #555555;
text-decoration: none;
transition: color 0.3s, text-decoration 0.3s;
}
.help-section a:hover {
color: #3a8ee6;
text-decoration: underline;
}
/* 小屏适配优化 */
@media (max-width: 400px) {
.form h2 {
font-size: 20px;
}
.help-section {
flex-direction: column;
align-items: center;
gap: 8px; /* 链接上下间距 */
}
}
</style>
<body>
<div class="form">
<h2>PPPoE上网账号_密码重置</h2>
<form method="post" action="password.asp" onsubmit="return validateForm();">
<label for="username">上网帐号:</label>
<input id="username" name="username" type="text" maxlength="64" />
<label for="newpwd">新的密码:</label>
<input id="newpwd" name="newpwd" type="password" maxlength="256" />
<label for="confpwd">确认密码:</label>
<input id="confpwd" name="confpwd" type="password" maxlength="256" />
<input class="btn" type="submit" value="确 认 密 码 重 置" />
<p></p>
</form>
</div>
</body>
</html>
技术架构图解流程:
用户提交表单→ASP 校验账号(SQL Server)→ASP调用 Shell 执行 trcli.exe→Radius 数据更新
功能亮点(代码解析)
- 安全性校验: 代码中检查了空字段、密码一致性以及最小长度限制,防止非法提交。
- 数据库预编译: 使用
ADODB.Command处理 SQL,有效防止了 SQL 注入。 - 解决路径空格难题: 在 Windows 环境下调用带空格的路径(如
C:\Program Files\...)是很多人的噩梦。代码中通过嵌套双引号""...""的方式解决了 WshShell.Exec 的路径识别问题。 - 前后端联动的交互: 前端用 JavaScript 做第一次拦截,后端做二次校验,最后用 alert 弹窗反馈结果并跳转。
界面设计
采用了 CSS 样式(Flexbox 布局、阴影效果、圆角),让 ASP 页面在移动端也能有不错的视觉体验。
部署注意事项(避坑指南)
- 权限问题:运行 IIS 的账号(如 IUSR)必须对
trcli.exe有执行权限。 - 驱动程序:确保服务器安装了 SQLNCLI10(SQL Server Native Client)。
- 路径配置:
TRCLI_PATH必须指向正确的安装位置。
结语
虽然 ASP 是老技术,但配合合适的 CLI 工具,依然是解决特定运维场景的最快路径。