Показать полную графическую версию : [решено] (C++ Builder) Программа аутентификации - проблема вызова диалоговых окон и сохранения
Здравствуйте, еще раз.
Помогите, пожалуйста, написать программу разграничения полномочий пользователей на основе парольной аутентификации.
Программу пишу в C++ Builder 6.
Условия задачи
1) Программа должна обеспечивать работу в двух режимах: администратора (пользователя с фиксированным именем ADMIN) и обычного пользователя.
2) Администратор может редактировать данные всех пользователей, включая свои. Пользователь может только менять свой пароль.
3) Данные о пользователях должны храниться в файле.
4) Интерфейс с программой должен быть организован на основе меню, и панели управления (желанно).
5) Для реализации указанных в пунктах 2 функций в программе должны использоваться специальные диалоговые формы, позволяющие пользователю (администратору) вводить необходимую информацию.
Большую часть функций программы я уже сделал (http://forum.oszone.net/thread-121836.html), осталось реализовать интерфейс и режим доступа пользователь/админ.
С этим есть небольшие проблемы, не могу понять, как из одного диалогового окна вызвать другое, в частности как сделать так, чтобы при щелчке в пункте меню «Смена пароля», открылось окно для смены пароля текущего пользователя (не стандартное, а созданное мной, допустим «Form3»).
И второе, как лучше реализовать сохранение текущей сессии, то есть, чтобы программа помнила под каким пользователем мы в нее зашли.
Я думал, что можно создать глобальную переменную, в которой хранить имя текущего пользователя, только не знаю как можно использовать эту переменную из разных форм.
Delirium
05-11-2008, 06:54
пункты 1-5:
http://rsdn.ru - Статьи - безопасность - Класс для работы с паролями. Язык немного отличается (.NET), но принцип должен быть понятен. Я как то использовал данный класс, тоже была авторизация для админа и пользователя с разграничением прав. И вообще полазийте по rsdn, данный форум очень авторитетен в плане программирования.
не могу понять, как из одного диалогового окна вызвать другое, в частности как сделать так, чтобы при щелчке в пункте меню «Смена пароля» »
Для этого необходимо проделать следующие шаги(пример на C#, главное смысл):
1. Скрытие основной формы (MainFrm.Hide())
2. Отображение Вашей формы ( ChildFrm.ShowDialog() или ChildFrm.ShowModal() )
3. В дочерней форме уже идет реализация того что вам нужно. Должна быть кнопка Выход или крестик закрытия формы.
4. После ChildFrm.ShowDialog() вновь отображаете Вашу основую форму MainFrm.Show()l
Вот примерно так.
При входе в программу запрашиваете имя и пароль. В случае успеха проверяете в своем файле, является ли данная учетка админской. Если да, то, например, можно отображать нужные пункты меню, либо, если это простой пользователь, ненужные ему опции можно сделать Disable.
Ну, это все понятно, только дело в том, что я не знаю, как в Билдере сделать окно дочерним, чтобы потом к нему можно было обращаться.
Алгоритм работы программы мне полностью понятен, вот только с реализацией не идет.
К примеру, я могу на действие "нажатие кнопки" поставить Form1->Visible=false;, тогда окно Form1 исчезнет, но это действие можно делать только внутри этой формы, а мне нужно, чтобы что-то подобное я мог сделать из другой формы.
То есть, мне нужно, чтобы при нажатии на кнопку в Form1, открывалась Form2.
Если я в обработчике нажатии кнопки, в Form1, пишу Form2->Visible=true, выдается ошибка, что он не знает что такое Form2. Значит к Form2 нужно как-то по другому обращаться, либо использоваться другое обращение.
Скорей всего для этого нужно использовать функцию какую-нибудь, возможно CreateDialog() или CreateWindowEx(). Только не знаю, что в эту функцию в качестве параметров вводить.
Delirium
05-11-2008, 07:59
ну тогда гугл в помощь:
http://wincmd.ru/article/ListSimpleBcb.html
цитата оттуда:
Чтобы создать дочернее окно воспользуемся статической функцией CreateParentedControl класса TWinControl, т.е. в теле функции функция ShowRTF воспользуемся следующим оператором:
fmMain = (TfmMain *)(TWinControl::CreateParentedControl(__classid(TfmMain), ListerWin));
либо сюда (http://forum.codenet.ru/showthread.php?t=39553)
ну или просто вот так (http://www.google.ru/search?hl=ru&lr=&newwindow=1&sa=X&oi=spell&resnum=0&ct=result&cd=1&q=C%2B%2B+Builder+6+%D0%B4%D0%BE%D1%87%D0%B5%D1%80%D0%BD%D1%8F%D1%8F+%D1%84%D0%BE%D1%80%D0%BC%D0%B0&spell=1)
Delirium, Спасибо!
а то я ищу ищу... и ничего полезного так и не нашел... Правда искал по другим ключевым полям.
Забавно.
Все оказалось гораздо проще. Нужно было всего лишь в Unit1.cpp добавить
#include "Unit2.h"
Тогда без проблем можно обращаться к Form2.
Подробней
В проекте есть две формы Form1 и Form2.
Их описание находятся в Unit1.cpp, Unit1.h и в Unit2.cpp, Unit2.h соответственно.
Также еще есть Project1.cpp и Project1.h, в этом файле находиться главная функция WinMain, которая срабатывает первой при запуске программы.
Важно чтобы в Project1.cpp были определенны обе формы
USEFORM("Unit1.cpp", Form1);
USEFORM("Unit2.cpp", Form2);
//---------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
Application->CreateForm(__classid(TForm2), &Form2);
Application->Run();
}
............
Изначально обращаться к формам можно только из них самих. Чтобы это исправить нужно просто в .cpp файл формы 1, из которой мы хотим обращаться к другой форме, включить .h файл формы 2.
Т.е. если мы хотим из Form1 обращаться к Form2, нужно в Unit1.cpp добавить
#include "Unit2.h"
После этого, в обраточике событий Form1 можно использоваться вызов Form2, к примеру так:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Form2->Visible=true;
}
Delirium
05-11-2008, 09:02
Радует, что Вы сами нашли решение своей проблемы, заодно заполнив небольшой пробельчик в знании языка :)
Если вопрос закрыт, отметьте тему решенной ("Настройки темы" вверху страницы - отметить решенной)
Delirium, Ну я еще не все сделал, возможно скоро еще вопросы появятся.
Как программа полностью доделаю, отпишусь здесь ;)
Еще не проверял по поводу того, где лучше хранить запись о текущем пользователе.
Я просто создал файл "users.h" с глобальной переменной (char session_user[16]), в которой храниться идентификатор пользователя. Этот файл прикрепил ко всем .cpp файлам проекта (#include "users.h"). Это сработало, хотя вроде бы так делать не очень правильно, у меня сразу вышло предупреждение:
[Linker Warning] Public symbol '_session_user' defined in both module D:\KEEPER\MY PROGS\LOGIN_PASS_0\UNIT1.OBJ and D:\KEEPER\MY PROGS\LOGIN_PASS_0\UNIT2.OBJ
Хотя стоить учесть, что программа носит чисто демонстрационный характер, для демонстрации аутентификации, а также работы с файлами, так что безопасность и эстетика реализации тут не так уж и важна.
PS
Спасибо что подсказал, как можно пометить тему что задача решена, а то я не знал, и об этом модераторов просил :)
Нет, не получилось использовать глобальную переменную для обмена информацией между Формами.
Делал так, есть две формы: Form1 и Form2.
Также есть файл "users.h", в котором находиться переменная для хранения имя пользователя.
В Form1 вводим имя пользователя, после чего открываем Form2 и там по этому имени (что мы ввели в Form1) должен происходить его поиск в файле. Но этого не происходит, т.к. Form1 не смог ни чего записать в эту переменную.
ниже привожу краткий листинг этих файлов:
users.h
#ifndef usersH
#define usersH
#include<iostream>
#include<fstream>
#include<string.h>
#include<stdlib.h>
#include<windows.h>
//Глобальная переменная для хранения имени пользователя
extern char session_user[16]="";
#endif
Unit1.cpp
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "Unit2.h"
#include "users.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
void __fastcall TForm1::Button1Click(TObject *Sender)
{
//Копируем то что ввели в Edit1 в переменную session_user
strcpy(session_user,Edit1->Text.c_str());
Form2->Visible=true;
Form1->Visible=false;
}
Unit2.cpp
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "Unit2.h"
#include "users.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
void __fastcall TForm2::Button1Click(TObject *Sender)
{
//ищем пользователя имя которого указана в session_user
find_u(session_user); //но ничего не происходит, т.к. session_user пустой
}
Delirium
06-11-2008, 01:03
Ну и не парьтесь вы с этими заголовками. Есть 2 варианта.
1. Самый тупой и простой - при вводе имени пользователя сохранять его в пустой текстовый файл. Если файл есть, переписать его. Таким образом, в текстовике всегда будет лежать имя последнего пользователя.
2. Сохранять имя не в файле, а в реестре, создать программно ветку в HKEY_CURRENT_USER\Software и также точно считывать.
Ну, я тоже думал об этом, но с этой проблемой я тоже уже разобрался ;)
Все отлично работает. Просто я немного напутал с определением глобальной переменной, давно этим не занимался и забыл как правильно делать.
Решил проблему так:
В основной форме, которая запускается первой и в которой изначально вводится имя пользователя (Unit1.cpp) создал обычную глобальную переменную: char session_user[16];
А в users.h уже определил ее как общую глобальную переменную: extern char session_user[16];. А так как users.h прикрепляется ко всем .cpp файлам проекта, то через него без проблем можно обращаться и к session_user.
Так что вроде бы все решил, одно но, выше описанный способ вызова одной формы из другой оказался не самым удачным, так как окна независимы и свободно перекрывают друг друга, в отличие от вызова дочерних окон, которые всегда высвечиваются поверх родительских.
Ну, это уже не так страшно, может и с этим еще удастся разобраться ;)
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.