ri_gilfanov
@ri_gilfanov
Web- and desktop-developer

Как отслеживать быструю подмену RFID-карты с Pyscard?

Есть считыватель RFID-карт и программа его использующая для авторизации пользователей.

В общем, пока зарегистрированная в системе RFID-карта лежит на считывателе, пользователь авторизован и может работать на машине. Как только карта убирается -- машина должна блокироваться.

Для работы со считывателем используется библиотека Pyscard.

Исходный код CardObserver`а:
from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
from smartcard.CardMonitoring import CardObserver
from smartcard.util import toHexString
from smartcard.Exceptions import NoCardException


class CardObserver(CardObserver):
    def __init__(self, app):
        self.app = app
        self.connection_observer = ConsoleCardConnectionObserver()
        self.has_card = False
        self.rfid_tag = None

    def update(self, observable, actions):
        connected_cards, disconnected_cards = actions
        for card in connected_cards:
            try:
                card.connection = card.createConnection()
                card.connection.connect()
                card.connection.addObserver(self.connection_observer)
                data, sw1, sw2 = card.connection.transmit([255, 202, 0, 0, 0])
                data.reverse()
                self.rfid_tag = toHexString(data, format=1)
                self.has_card = True
            except NoCardException:
                print('Ошибка. Карта обнаружена, но убрана до прочтения.')

        if disconnected_cards:
            self.rfid_tag = None
            self.has_card = False


Всё работает неплохо, но есть одна проблема.

Пользователь может быстро подменить свою RFID-карту на другую (даже незарегистрированную в системе), тогда CardMonitor может не заметить подмены и не оповестить CardObserver, а значит не будет вызван метод update и новая RFID-метка не будет проверена на предмет регистрации в системе.

Заказчика такое поведение не устраивает.

Кто-нибудь знает самый оптимальный и стабильный способ это исправить?

Я склоняюсь к мысли отказаться от готового классов CardMonitor и CardObserver из Pyscard, а написать свой, что будет в отдельном потоке ежесекундно опрашивать считыватель карт и ежесекундно читать RFID-метку с положенной карты.

Ещё думал приделать отдельный поток к текущей реализации сбоку, в котором RFID-метка только для положенной карты будет перезапрашиваться каждые несколько секунд. Так что внутри метода update, если карта лежит -- поток ежесекундного чтения RFID-метки запускается, если карта убрана -- поток останавливается. На текущий момент, до корректно работающего решения не дошёл.
  • Вопрос задан
  • 191 просмотр
Решения вопроса 1
ri_gilfanov
@ri_gilfanov Автор вопроса
Web- and desktop-developer
Переписал кастомный CardObserver таким образом:
from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
from smartcard.CardMonitoring import CardObserver
from smartcard.util import toHexString
from smartcard.Exceptions import CardConnectionException, NoCardException
from time import sleep


class CardObserver(CardObserver):
    def __init__(self, app):
        self.app = app
        self.connection_observer = ConsoleCardConnectionObserver()
        self.has_card = False
        self.rfid_tag = None
        self.card = None

    def update(self, observable, actions):
        connected_cards, disconnected_cards = actions
        if connected_cards:
            self.card = connected_cards[0]
            self.get_rfid_tag()

        for card in disconnected_cards:
            self.rfid_tag = None
            self.has_card = False
            self.card = None

    def get_rfid_tag(self):
        try:
            self.card.connection = self.card.createConnection()
            self.card.connection.connect()
            self.card.connection.addObserver(self.connection_observer)
            data, sw1, sw2 = self.card.connection.transmit([255, 202, 0, 0, 0])
            data.reverse()
            self.rfid_tag = toHexString(data, format=1)
            self.has_card = True
        except NoCardException as error:
            print(error)
        except AttributeError as error:
            print(error)
        except CardConnectionException as error:
            print(error)

    def rfid_tag_check_worker(self):
        while True:
            if self.card:
                self.get_rfid_tag()
            sleep(5)


И при запуске приложения, создаю дополнительный поток, вызывающий функцию rfid_tag_check_worker.

rfid_tag_check_thread = Thread(target=self.rfid_card_observer.rfid_tag_check_worker)
rfid_tag_check_thread.start()


Пока вроде работает корректно, хотя к картридеру обращаются два потока.

Потестирую с меньшими интервалами проверки, надеюсь это стабильное в работе решение.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
26 мая 2020, в 02:01
4500 руб./за проект
26 мая 2020, в 00:42
10000 руб./за проект
25 мая 2020, в 22:16
3000 руб./за проект