Dart学生门户登录:修改NTLMClient传递CSRF令牌方案咨询
解决方案:结合NTLMClient与CSRF令牌传递
可以不用无头浏览器,只需调整NTLMClient的使用流程,先获取CSRF相关令牌再发起登录请求即可。核心思路是复用NTLMClient实例保持会话,先GET登录页面提取CSRF字段,再携带这些字段发起POST登录请求,具体步骤和代码如下:
关键逻辑说明
- NTLM会话保持:NTLMClient会自动处理NTLM认证的握手流程,必须复用同一个实例维护会话cookie,否则CSRF令牌会因会话不匹配失效。
- CSRF字段提取:ASP.NET的CSRF防护依赖
__VIEWSTATE、__EVENTVALIDATION、__VIEWSTATEGENERATOR这些隐藏字段,必须从登录页面的HTML中解析获取。 - 请求头对齐:确保请求头(User-Agent、Content-Type)与浏览器一致,避免被服务器拦截。
修改后的登录代码
import 'package:http/http.dart' as http; import 'package:html/parser.dart' show parse; import 'package:html/dom.dart'; import 'package:ntlm/ntlm.dart'; import 'package:my_portal/globals.dart' as globals; Future<bool> loginGUC(String username, String password) async { // 创建NTLMClient实例,复用会话 final client = NTLMClient( domain: "", workstation: "", username: username, password: password, ); try { // 第一步:GET登录页面,获取CSRF字段和会话cookie final loginPageResponse = await client.get( Uri.parse('https://portal.giu-uni.de/GIUb/EXTStudent/Home.aspx'), headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' }, ); if (loginPageResponse.statusCode != 200) { print('Failed to load login page'); client.close(); return false; } // 解析HTML,提取CSRF相关字段 final document = parse(loginPageResponse.body); String _getInputValue(String inputName) { final input = document.querySelector('input[name="$inputName"]'); return input?.attributes['value'] ?? ''; } final viewState = _getInputValue('__VIEWSTATE'); final eventValidation = _getInputValue('__EVENTVALIDATION'); final viewStateGenerator = _getInputValue('__VIEWSTATEGENERATOR'); // 第二步:构造登录表单数据,携带CSRF字段 final loginData = { '__VIEWSTATE': viewState, '__EVENTVALIDATION': eventValidation, '__VIEWSTATEGENERATOR': viewStateGenerator, '__EVENTTARGET': '', '__EVENTARGUMENT': '', 'username': username, 'password': password, }; // 发起POST登录请求 final loginResponse = await client.post( Uri.parse('https://portal.giu-uni.de/GIUb/EXTStudent/Home.aspx/login'), headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' }, body: loginData, ); // 检查登录是否成功 bool isLoggedIn = loginResponse.body.contains('Home.aspx'); if (isLoggedIn) { globals.username = username; globals.password = password; } client.close(); return isLoggedIn; } catch (e) { print('Login error: $e'); client.close(); return false; } }
额外注意事项
- 如果NTLMClient未自动管理cookie,可复用你现有
GIUPortalLogin类中的_updateCookies和_formatCookies方法,手动提取并携带cookie。 - 若登录接口的URL不是
Home.aspx/login,请根据页面表单的action属性调整。 - 部分ASP.NET站点会在NTLM认证后才返回带CSRF字段的页面,此代码已覆盖该场景。
内容的提问来源于stack exchange,提问作者abtlb
相关产品推荐
相关产品推荐

