- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在获取 csrf token 并在控制台中打印响应数据,但如何使用响应数据保持用户登录。我正在使用状态代码进行登录,即,如果状态代码为 200,则在之后转到登录希望保持用户登录状态并仅在用户想要注销时注销
我看过很多例子,但没有一个对我的情况有帮助。
就我而言,我使用的是 csrf token ,无法保持登录状态,而且我还使用了登录表单。
登录页面.dart
import 'dart:io';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:jignasa/home_screen.dart';
import 'package:jignasa/logindata.dart';
import 'package:path_provider/path_provider.dart';
class LoginPage extends StatefulWidget {
static String tag = 'login-page';
@override
_LoginPageState createState() => new _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
LoginRequestData _loginData = LoginRequestData();
bool _validate = false;
bool _obscureText = true;
var username, password;
@override
Widget build(BuildContext context) {
return Scaffold(
// backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Container(
color: Colors.lightGreen[500],
child: Column(
children: <Widget>[
Center(
child: Container(
width: MediaQuery
.of(context)
.size
.width,
height: MediaQuery
.of(context)
.size
.height / 2.5,
decoration: BoxDecoration(
gradient: LinearGradient(
// begin: Alignment.topCenter,
// end: Alignment.bottomCenter,
colors: [
Color(0xFFFFFFFF),
Color(0xFFFFFFFF),
]
),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(90)
)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Align(
alignment: Alignment.center,
child: Image.asset('images/ic_launcher1.png'),
),
],
),
),
),
Center(
child: SingleChildScrollView(
child: new Form(
key: _formKey,
autovalidate: _validate,
child: _getFormUI(),
),
)
)
],
),
),
),
);
}
Widget _getFormUI() {
return new Column(
children: <Widget>[
SizedBox(height: 24.0),
Center(
child: Text('Login',
style: TextStyle(fontSize: 25,
fontWeight: FontWeight.bold,
color: Colors.white),),
),
new SizedBox(height: 25.0),
new TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
decoration: InputDecoration(
hintText: 'Username',
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(32.0)),
),
validator: _validateName,
onSaved: (value) {
_loginData.username = value;
},
),
new SizedBox(height: 8.0),
new TextFormField(
autofocus: false,
obscureText: _obscureText,
keyboardType: TextInputType.text,
decoration: InputDecoration(
hintText: 'Password',
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(24.0)),
suffixIcon: GestureDetector(
child: Icon(
_obscureText ? Icons.visibility : Icons.visibility_off,
semanticLabel:
_obscureText ? 'show password' : 'hide password',
),
),
),
validator: _validatePassword,
onSaved: (String value) {
_loginData.password = value;
}
),
new SizedBox(height: 15.0),
new Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
onPressed: () {
_submit();
// Navigator.of(context).pushReplacementNamed('/home');
},
padding: EdgeInsets.all(12),
color: Colors.black54,
child: Text('Log In', style: TextStyle(color: Colors.white)),
),
),
new FlatButton(
child: Text(
'Forgot password?',
style: TextStyle(color: Colors.black54),
),
onPressed: () {},
),
new FlatButton(
onPressed: _sendToRegisterPage,
child: Text('Not a member? Sign up now',
style: TextStyle(color: Colors.black54)),
),
Text(''),
Text(''),
Text(''),
],
);
}
_sendToRegisterPage() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomeScreen()),
);
}
String _validateName(String value) {
if (value.isEmpty) {
return "Username is Required";
} else {
username = value.toString();
}
}
String _validatePassword(String value) {
if (value.isEmpty) {
return "Password is Required";
} else {
password = value.toString();
}
}
_submit() {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
print("Username ${_loginData.username}");
print("Password ${_loginData.password}");
return SessionId();
} else {
setState(() {
bool _validate = false;
});
}
}
final Dio _dio = Dio();
PersistCookieJar persistentCookies;
final String url = "https://www.xxxx.in/rest/user/login.json";
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
print(directory.path);
return directory.path;
}
Future<Directory> get _localCoookieDirectory async {
final path = await _localPath;
final Directory dir = new Directory('$path/cookies');
await dir.create();
print(dir);
return dir;
}
Future<String> getCsrftoken() async{
try {
String csrfTokenValue;
final Directory dir = await _localCoookieDirectory;
final cookiePath = dir.path;
persistentCookies = new PersistCookieJar(dir: '$cookiePath');
persistentCookies.deleteAll(); //clearing any existing cookies for a fresh start
_dio.interceptors.add(
CookieManager(persistentCookies) //this sets up _dio to persist cookies throughout subsequent requests
);
_dio.options = new BaseOptions(
baseUrl: url,
contentType: ContentType.json,
responseType: ResponseType.plain,
// connectTimeout: 5000,
// receiveTimeout: 100000,
headers: {
HttpHeaders.userAgentHeader: "dio",
"Connection": "keep-alive",
},
); //BaseOptions will be persisted throughout subsequent requests made with _dio
_dio.interceptors.add(
InterceptorsWrapper(
onResponse:(Response response) {
List<Cookie> cookies = persistentCookies.loadForRequest(Uri.parse(url));
csrfTokenValue = cookies.firstWhere((c) => c.name == 'csrftoken', orElse: () => null)?.value;
if (csrfTokenValue != null) {
_dio.options.headers['X-CSRF-TOKEN'] = csrfTokenValue; //setting the csrftoken from the response in the headers
}
print(response);
return response;
}
)
);
await _dio.get("https://www.xxxx.in/rest/user/login.json");
print(csrfTokenValue);
return csrfTokenValue;
} catch (error, stacktrace) {
print(error);
// print("Exception occured: $error stackTrace: $stacktrace");
return null;
}
}
SessionId() async {
try {
final csrf = await getCsrftoken();
FormData formData = new FormData.from({
"username": "${_loginData.username}",
"password": "${_loginData.password}",
"csrfmiddlewaretoken" : '$csrf'
});
Options optionData = new Options(
contentType: ContentType.parse("application/json"),
);
Response response = await _dio.post("https://www.xxxx.in/rest/user/login.json", data: formData, options: optionData);
print("StatusCode:${response.statusCode}");
// print(response.data);
if (response.statusCode == 200){
return Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => HomeScreen(),
));
}
else{
throw Exception();
}
} on DioError catch(e) {
if(e.response != null) {
print( e.response.statusCode.toString() + " " + e.response.statusMessage);
print(e.response.data);
print(e.response.headers);
print(e.response.request);
} else{
print(e.request);
print(e.message);
}
}
catch (error, stacktrace) {
print("Exception occured: $error stackTrace: $stacktrace");
return null;
}
}
}
最佳答案
从 api 获取响应代码 200 后,您可以在共享首选项中进行输入。
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs?.setBool("isLoggedIn", true);
然后您可以在从共享首选项检查状态后导航用户
Future<void> main() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var status = prefs.getBool('isLoggedIn') ?? false;
print(status);
runApp(MaterialApp(home: status == true ? Login() : Home()));
}
更新:-
另一种方法是您还可以将逻辑添加到启动屏幕中,并且启动屏幕应该是应用程序中的入口点
class SplashScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _SplashScreenState();
}
}
class _SplashScreenState extends State<SplashScreen> {
@override
void initState() {
// TODO: implement initState
super.initState();
startTimer();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/clinician_splash.png"),
fit: BoxFit.cover),
),
),
);
}
void startTimer() {
Timer(Duration(seconds: 3), () {
navigateUser(); //It will redirect after 3 seconds
});
}
void navigateUser() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
var status = prefs.getBool('isLoggedIn') ?? false;
print(status);
if (status) {
Navigation.pushReplacement(context, "/Home");
} else {
Navigation.pushReplacement(context, "/Login");
}
}
}
对于注销,在注销按钮的 onPress 事件中添加以下功能:
void logoutUser(){
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs?.clear()
Navigator.pushAndRemoveUntil(
context,
ModalRoute.withName("/SplashScreen"),
ModalRoute.withName("/Home")
);
}
为了安全:-
在示例中,我使用了不安全的 SharedPreferences。为了安全起见,您可以将 SharedPreferences 更改为 flutter_secure_storage。
https://pub.dev/packages/flutter_secure_storage#-readme-tab-
关于authentication - flutter : How to keep user logged in and make logout,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57405433/
好吧,我读了 Facebook 建议,告诉我最好是当用户从我的网站注销时关闭 Facebook session 。 信息在这里:https://developers.facebook.com/docs
我使用的是 Django 1.6.1,我在 /admin 处收到此错误该项目是一个新项目,没有使用其他模型。 Reverse for 'logout' with arguments '()' and
我对使用 passport-saml 进行身份验证时注销用户的正确方法有疑问。 带有 passport-saml 的示例脚本显示注销如下: app.get('/logout', function(re
我已经用 Spring Security 3.0.2 实现了一个登录-注销系统,一切都很好,但是对于这一点:在我添加了一个带有 invalid-session-url 属性的 session 管理标签
使用Phoenix框架,如何在用户注销并按下浏览器后退按钮后阻止用户访问之前的页面? 最佳答案 浏览器能够访问该页面是因为默认情况下允许缓存响应。如果您想防止这种情况发生,您需要在需要身份验证的页面上
我正在尝试通过第三方单一登录提供程序(例如rpxnow)提供身份验证功能。登录页面的每次刷新后,我无法检索提供者设置的cookie,因此当用户希望注销时可以删除它们吗? 还有其他方法可以正常注销用户,
当我调试ssh时,我发现“logout”的返回值是他之前的命令。例如, [server1 ~] $ ssh root@server2 /* login server2 from server1 *
使用with语句时,是否需要调用imap4类的close和logout方法? docs不要提供太多上下文。 Changed in version 3.5: Support for the with s
我正在使用云代码,并且有两个 Parse 帐户。我已经授权了第一个 Parse 帐户,但我想将云代码添加到新的 Parse 帐户,但每当我执行 Parse add 时,它会自动将我带到我拥有的 par
我想弄清楚如何覆盖 auth_views.logout 方法。通常我在覆盖类方法方面不会有问题,但是我意识到我正在尝试覆盖一个 View ,这可以在 Django 中做到吗? 我想覆盖 View 的原
我希望用户能够通过 HTTP 基本身份验证模式登录。 问题是我还希望他们能够再次注销 - 奇怪的是浏览器似乎不支持这一点。 这被认为是一种社交黑客风险 - 用户将其计算机解锁并打开浏览器,其他人可以轻
编写一个小代码 fragment ,其中 ParseUser 在满足某些条件后注销。有时它工作得很好,有时它会抛出如下所示的类转换期望 java.lang.classcastexception: or
有没有办法在页面首次加载时运行 FB.logout()?还是只有当用户点击它并触发它时才有可能?谢谢! 最佳答案 您不需要 jQuery,只需在您的 window.fbAsyncInit 函数中添加对
当我编写每个 C++ 程序时,例如那个程序: #include #include using namespace std; int main() { int n; cout > n
我使用 Django 函数进行登录,但它不显示我的模板。代码在这里: Views.py class Logout(View): #import pdb; pdb.set_trace()
我为我的 Spring Boot 应用程序实现了 JWT 身份验证。总的来说,它是这样工作的: 客户端将用户名、密码发送到登录端点。 服务器检查提供的凭据是否有效。 如果不是,它将返回一个错误 如果是
Laravel 自动授权讲解 看到这部分文档,经常看见的一句话就是php artisan make:auth,经常好奇这段代码到底干了什么,现在就来扒一扒。 路由 路由文件中会新加入以下内容:
我在我的应用程序中使用 AWS Cognito。 在注销时,我正在调用 Logout Endpoint . 但是在注销后,我仍然可以使用旧的刷新 token 生成 id-tokens。 这意味着我的注
我在服务器端有两种方法,如下所示: var Future = require("fibers/future"); Meteor.methods({ foo: function () {
我有一个使用默认 Lotus Notes http 登录的 Lotus Notes 应用程序。 在我们的开发者服务器上,Notes 有一个将登录请求发送到 names.nsf 的 html 表单 注
我是一名优秀的程序员,十分优秀!