簡體   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