본문 바로가기

Studying/Python

22. miniProject(12) - password manager (feat.tkinter)

이번에는 좀 복잡한 프로젝트를 해보자. 

 

website 별로 우리는 이메일 혹은 이름을 입력하고 비밀번호를 저장하여 관리하는 password manager를 만들 것이다. 

 

여기서 우리는 비밀번호를 우리가 직접 입력할수도, 아님 랜덤으로 만들 수도 있다. 

 

그리고 홈페이지 별 사용자 이름과 비밀번호를 json 파일로 저장하여 관리할 것이고 비밀번호 찾기 기능을 구현할 것이다. 

 

크게 랜덤 비밀번호를 생성하는 기능, 비밀번호와 이메일을 json 파일로 저장하는 기능, 저장했던 json 파일에서 비밀번호를 찾는 기능, 그리고 tkinter 창의 widget 을 구현하는 과정으로 나누어서 진행할 것이다. 

 


먼저 랜덤 비밀번호를 생성하는 함수를 작성해보자. 

 

무작위로 비밀번호를 만드는 generate_password() 함수이다. 

 

비밀번호에 들어갈 letters, numbers, symbols 를 각각 list 형태로 준비하고 각각 randint 를 사용하여 choice 하고 이 결과를 각각 password_letters, password_symbols, password_numbers 에 저장한다. 

 

세 변수에 저장한 것을 password_list 라는 변수로 합치고 이를 shuffle 을 통해 섞는다.

( 이 상태는 list 의 개별 값으로 존재하므로 join 을 사용한다. )

 

이렇게 만들어진 비밀번호를 password 로 저장하고, 나중에 widget 으로 만들 password_entry 에 넣는다. 

( insert(index, "문자열") - 해당 index 위치에 "문자열" 을 삽입한다. ) 

 

pyperclip 는 복사와 붙여넣기를 위해 클립보드 기능 사용을 위한 크로스 플랫폼 module 이다. 

( pip install pyperclip ) 

 

이를 사용해 랜덤으로 생성된 비밀번호를 나중에 복사할 수 있도록, pyperclip.copy(password) 를 한다. 

 

랜덤으로 비밀번호를 만들었으면 이제 저장해야한다. 우린 json 형식으로 저장할 것이다. 

 

 

tkinter 로 열린 창, 그리고 entry에 입력된 사이트, 이름 및 비밀번호를 저장하는 과정은 먼저 save() 함수로 선언할 것이다. 

 

이 함수와 tkinter 에서 버튼을 클릭했을 시 실행될 함수를 지정할 때 연결해줄 것이다. 

 

우리가 json 파일로 저장할 양식엔 홈페이지, 이메일, 비밀번호를 각각 tkinter 값에서 가져와 

 

"website 이름" : {  

                    "email" : email,

                    "password" : password

}

 

위와 같은 형식을 정할 것이다. 

 

따라서, website, email, password 라는 변수로 각각의 tkinter_entry 에서 값을 get() 해서 저장한다. 

 

그리고 이 값들을 new_data 라는 dictionary 로 위의 양식에 맞게 저장한다. 

 

그런데 만약 우리가 아무것도 입력하지 않은 entry 가 존재할 경우에는 저장이 되지 않게 하고 싶다면 어떻게 할까?

 

그럴 경우를 위해 if 문을 사용한다. 

 

website 또는 password 에 입력내용이 없어 len 이 0일 경우, messagebox.showinfo 를 사용해 팝업 메세지 창을 나타나게 만든다. 

( messagebox 도 tkinter 에 포함된 module 이다. showinfo 의 경우 별도 예, 아니오 선택 창이 아닌 단순 알림 창이다. )

 

만약 len 이 0이 아닐 경우에는, data.json 파일을 다뤄야한다. 

 

이 때, 우리는 try, except, else, finally 문을 사용하여 상황별로 작성할 것이다. 

 

try 에는 기본적으로 실행되는 코드를 입력하고 except 에는 try 문에서 에러가 발생했을 경우에 시행할 코드를 작성한다. 

 

else 에는 try 에서 예외가 발생하지 않아 except 절을 실행하지 않았을 경우에 실행되는 코드를 입력한다. 

 

마지막 finally 에는 try 절의 예외 발생여부와 관계없이 항상 실행될 구문을 입력한다. 

 

그렇다면 우리는 어떻게 상황을 구분해야할까?

 

먼저 try 에는 data.json 파일을 읽기모드로 여는 것을 작성한다. 

 

만약 data.json 파일이 없을 경우  즉, try 문에서 오류가 날 경우 ( FileNotFoundError ) "data.json" 파일을 쓰기모드로 생성하게 만든다.  

 

그렇다면 try 문이 예외발생이 아니라면, 즉 이미 data.json 이 있었고 이를 읽기모드로 열었다면, else 문을 사용해서 그 파일을 다시 쓰기모드로 열고 우리가 원했던 양식을 json 문자열로 변환하여 저장시킨다. ( json.dumps() )

 

마지막으로 try 와는 상관없이 무조건 실행될 내용으로 finallytkinter의 entry 를 비우는 코들르 작성한다. 

 

자 이제 비밀번호를 찾는 기능을 구현해보자.

 

머리속으로 구상을 해보면 우리가 어떤 홈페이지의 비밀번호를 등록했었는지 모르겠는 경우, 비밀번호 찾기를 한다고 상상해보자. 

 

그 때 우리는 website_entry 에 해당 웹사이트 이름을 입력하고 search_button 을 눌러 확인을 하게 될 것이다. 

 

즉 해당 내용을 "data.json" 파일에서 찾으면 될 것이다. 

 

 

이 모든 과정을 find_password() 라는 함수 내부에 선언할 것이다. 

 

비밀번호가 궁금한 웹사이트 이름을 입력하고, 그 값을 get 을 사용해 website에 저장한다. 

 

이 떄 역시 try, except, else 문을 사용할 것이다. 

 

먼저 try 절에 "data.json" 파일을 data_file 라는 이름으로 저장해 열고 data_file 에 있는 내용을 data로 저장한다. 

 

만약 try 에서 FileNotFoundError 가 발생할 경우, messagebox 를 사용하여 data.json 파일이 없다는 것을 알려준다. 

 

try 에서 에러가 발생하지 않을 경우, else 문을 사용하여 비교를 시작한다. 

 

비밀번호가 궁금했던 websitedata에 있다면 ( if ), 그 data의 keyvalue 를 이용하여 emailpassword 를 불러온다. 

 

그리고 그 불러온 email과 password를 messagebox로 띄워준다. 

 

만약 없다면, ( else ) 해당 website 에는 세부내용이 없다는 것을 마찬가지로 messagebox 로 띄운다. 

 

이제 UI 들을 설정해야한다. 

 

tkinter 를 사용하는 코드는 아래와 같다. 

 

특별히 새로운 것은 없고 우리가 기억해야할 것은 tkinter.Button( text=" ", command=함수)gird 의 내용이다. 

 

grid 는 앞 게시물에서도 설명했지만 rowcolumn 을 기준으로 위젯의 위치를 결정하는 것이다. 

 

추가적으로 만약 한칸에 그치지 않고 두칸 이상을 차지하도록 설정하려면 어떻게 해야할까?

 

row=1, column=1 에 설정한 상태에서 columnspan=2 로 추가 설정을 주면, column 을 2칸 1부터 2까지 차지하게 된다. 

 

Button 의 경우 버튼에 입력할 text와 눌렀을 경우 실행될 함수를 command 로 입력한다. 

 

실행화면