繁体   English   中英

current_user.is_authenticated 始终为 False(TACACS 和 flask_login)

[英]current_user.is_authenticated always False (TACACS and flask_login)

概括

我正在尝试实现基于 TACACS+ 的 flask_login 系统,但由于current_user.is_authenticated始终为 false,因此我被卡住了。 我没有使用任何本地数据库 - 通过我的登录表单提交的用户名和密码直接传递给 TACACS。

我的自定义User类实现了 此处flask_login 文档中描述的 3 个属性和 1 个方法:

下面,您将找到每个文件的相关代码,以便您可以在自己的环境中进行设置。

下面有很多信息,所以我想尽可能清楚地分享我的实际问题:

如何将我的自定义User类连接到current_user代理?

我的实现的潜在问题是,当我使用@login_required装饰器访问任何烧瓶路由时,应用程序认为用户未登录并将其重定向到登录页面。 我已经确定它是因为current_user.is_authenticated属性从不为 True。


应用程序

from flask import Flask, request, render_template, url_for, flash, redirect, session, Markup
from forms import LoginForm
from flask_login import LoginManager, login_user, logout_user, login_required, current_user, UserMixin
import user_auth as auth

# TODO: Save the user_dict to a pickle file so that users persist between service restarts
user_dict = {}

class User():
    def __init__(self, username, password):
        self.username = username
        self.password = password

        # Send TACACS authentication and authorization requests
        priv = auth.login(self.username, self.password)

        if priv:
            self.is_authenticated = True
            self.is_active = True
            self.is_anonymous = False
            if priv == 'admin':
                self.priv_lvl = 15
            elif priv == 'user':
                self.priv_lvl = 10
            elif priv == 'employee':
                self.priv_lvl = 5                
        else:
            self.is_authenticated = False
            self.is_anonymous = True
            self.priv_lvl = -1

    def get_id(self):
        return self.username

app = Flask(__name__)
app.secret_key = 'mysecretkey!'
app.static_url_path = 'static/'    

login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'index'    

@login_manager.user_loader
def load_user(user):
    global user_dict
    if user in user_dict.keys():
        return user_dict[user]

@app.route('/', methods=['GET', 'POST'])
def index():
    form = LoginForm()

    try:
        if user.is_authenticated:
            return render_template('test.html')
    except UnboundLocalError:
        user = None
        pass

    if form.validate_on_submit():
        username = form.username.data
        password = form.password.data
        user = User(username, password)
        username = password = None
        print(f"User {user.username} logged in. User authenticated: {user.is_authenticated}")
        print(f"Is current_user authenticated? {current_user.is_authenticated}")

        if user.priv_lvl >= 0:
            # SOLUTION -> The following was missing
            login_user(user, remember=form.remember.data)
            user_dict.update({
                user.username : user
            })
            # END SOLUTION
            print("User is authorized to view test.html.")
            return render_template('test.html', current_user=current_user, user=user)        

        else:
            flash(f'Invalid login', 'error')
            return render_template('index.html', title='Login Required', form=form, user=user)

    return render_template('index.html', title='Login Required', form=form, user=user)

@app.route("/home", methods=['GET'])
@login_required
def home():
    return render_template('test.html')

user_auth.py

from tacacs_plus.client import TACACSClient
from tacacs_plus.flags import TAC_PLUS_ACCT_FLAG_START, TAC_PLUS_ACCT_FLAG_WATCHDOG, TAC_PLUS_ACCT_FLAG_STOP
import socket


ISE = 'my.ip.add.rr'
auth_key = 'password'

def login(username, password):
    cli = TACACSClient(ISE, 49, auth_key, timeout=10, family=socket.AF_INET)
    authen = cli.authenticate(username, password)
    if authen.valid:
        author = cli.authorize(username, arguments=[b"service=", b"protocol="])
        if author.valid:
            role = author.arguments[0].decode('utf-8')
            if 'user' in role.lower():
                priv = 'user'
            elif 'admin' in role.lower():
                priv = 'admin'

        else:
            print("User has authenticated successfully, but failed authorization.")
            priv = 'employee'
    else:
        print("User failed authentication.")
        priv = None

    return priv

表格.py

from flask_wtf import FlaskForm
from wtforms import Form, StringField, SubmitField, BooleanField
from wtforms.fields import PasswordField
from wtforms.validators import DataRequired

class LoginForm(FlaskForm):
    username = StringField("Username", validators=[DataRequired()])
    password = PasswordField("Password", validators=[DataRequired()])
    remember = BooleanField("Remember Me")
    submit = SubmitField("Login")

索引.html

<div id='login-container' class='container'>
  <form method="POST" action="">
    {{ form.csrf_token }}
    {{ form.hidden_tag() }}
    <fieldset>
        <legend class="border-bottom mb-4">Login</legend>
        <p>Use your TACACS credentials.</p>


        {% with messages = get_flashed_messages() %}
          {% if messages %}
          <div class="alerts">
            {% for message in messages %}
            <div class="alert alert-warning" role="alert">{{ message }}</div>
            {% endfor %}
          </div>
          {% endif %}
        {% endwith %}

        <div class='form-group'>
          {{ form.username.label(class="form-control-label") }}
            {% if form.username.errors %}
            {{ form.username(class="form-control form-control-lg is-invalid") }}
            <div class='custom-invalid-feedback'>
                {% for error in form.username.errors %}
                <span>
                    {{ error }}
                </span>
                {% endfor %}
            </div>
            {% else %}
            {{ form.username(class="form-control form-control-lg") }}
            {% endif %}
        </div>

        <div class='form-group'>
          {{ form.password.label(class="form-control-label") }}
            {% if form.password.errors %}
            {{ form.password(class="form-control form-control-lg is-invalid") }}
            <div class='custom-invalid-feedback'>
                {% for error in form.password.errors %}
                <span>
                    {{ error }}
                </span>
                {% endfor %}
            </div>
            {% else %}
            {{ form.password(class="form-control form-control-lg") }}
            {% endif %}
        </div>

        {{form.remember.label}}  
        {{form.remember}}
        <div class="form-group">
            {{ form.submit(class="btn btn-outline-info") }}
        </div>
    </fieldset>
</form>  
</div>

测试.html

{% if user.is_authenticated %}
    <h2>My custom user class is authenticated</h2>
{% else %}
    <h2> My custom user class is NOT authenticated</h2>
{% endif %}

{% if current_user.is_authenticated %}
    <h2> current_user is authenticated</h2>
{% else %}
    <h2>current_user is NOT authenticated</h2>
{% endif %}

requirements.txt(以防您想在自己的环境中进行测试)

Jinja2==2.10
dominate==2.5.1
Flask==1.1.1
flask_login==0.5.0
flask_wtf==0.14.3
plotly==4.5.3
tacacs_plus==2.6
WTForms==2.2.1

注意:如果您想在自己的应用程序中进行测试并且不想打扰 TACACS,请手动将priv设置为adminuser


当我使用有效凭据登录时,这是我从控制台看到的内容:

User LetMeIn logged in. User authenticated: True
Is current_user authenticated? False
User is authorized to view test.html.

...在我浏览器的 test.html 页面上,我看到

html_输出


我在第四次剖析我的代码后想通了。

简单地说,我错过了 login_user() 函数调用。 这是将自定义 User 类关联到 flask_login current_user关联的原因。

我还需要创建一个简单的本地用户名存储方法,以便所需的load_user函数可以正常工作。 为此,我添加了一个全局可访问的字典,该字典将我的自定义 User 对象存储为与保存用户名的键相关联的值。

我将使用这些更改更新我原始帖子中的代码片段,希望我的努力将来对某人有用。 我在网上找不到太多关于将 TACACS 与flask_login 集成的信息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM