코드를 여러 개의 파일로 나누면 유지보수와 확장이 용이해집니다. 다음과 같이 파일을 분리할 수 있습니다.
코드 분리하면서 소스코드 안에 search_base = 'dc=gsoft,dc=local' 값을 로그인할 때 서버의 FQDN 값을 받아 처리 하도록 변경 함.
- authenticate.py: 인증 관련 함수
- login_page.py: 로그인 페이지
- main_page.py: 메인 페이지
- change_password_page.py: 비밀번호 변경 페이지
- app.py: 메인 어플리케이션 실행 파일
각 파일의 내용은 다음과 같습니다:
authenticate.py: 인증 관련 함수
import ssl
from ldap3 import Server, Connection, ALL, Tls
import streamlit as st
def authenticate(server, username, password, baseDN):
try:
tls_configuration = Tls(validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1_2)
server = Server(server, use_ssl=True, get_info=ALL, tls=tls_configuration)
conn = Connection(server, user=username, password=password)
if conn.bind():
return True
else:
return False
except Exception as e:
st.error(f"인증 오류 : {str(e)}")
return False
login_page.py: 로그인 페이지
import streamlit as st
from authenticate import authenticate
def login_page():
st.title('Active Directory 로그인 페이지')
username = st.text_input('로그인 ID', placeholder='AccountID@domain.local 형식으로 입력해 주세요.')
password = st.text_input('비밀번호', type='password')
server = st.text_input('서버 FQDN', placeholder='servername.domain.local 형식으로 입력해 주세요.')
# server 값으로 받은 FQDN 값을 . 으로 분류하여 part 변수에 배열 값으로 설정
parts = server.split(".")
# 서버명은 cn 임으로 배열 0 번째 값에는 cn= 를 붙이고 나머지 값은 for 문으로 dc= 값을
# 결과 ['cn=server', 'dc=gsoft', 'dc=local']
modified_strings = [f'cn={parts[0]}'] + [f'dc={parts}' for parts in parts[1:]]
# dc= 값만 추출하여 dc 변수에 저장
# 결과 ['dc=gsoft', 'dc=local']
dc = [part for part in modified_strings if part.startswith('dc=')]
# baseDN 변수에 join 함수를 사용하여 , 로 합치기
# baseDN 변수에 dc=gsoft,dc=local 값이 저장
baseDN = ',' .join(dc)
if st.button('로그인'):
if not username:
st.error("로그인 ID를 입력하세요.")
elif not password:
st.error("비밀번호를 입력하세요.")
elif not server:
st.error("서버 이름 혹은 IP를 입력하세요.")
else:
if authenticate(server, username, password, baseDN):
st.session_state['authenticated'] = True
st.session_state['server'] = server
st.session_state['username'] = username
st.session_state['password'] = password
st.session_state['baseDN'] = baseDN
st.session_state['page'] = 'main'
st.rerun()
else:
st.error('로그인 실패')
main_page.py: 메인 페이지
import ssl
from ldap3 import Server, Connection, ALL, Tls
import streamlit as st
def main_page(server, username, password, baseDN):
if st.button('로그아웃'):
st.session_state['authenticated'] = False
st.session_state['server'] = None
st.session_state['username'] = None
st.session_state['password'] = None
st.session_state['baseDN'] = None
st.rerun()
st.title('Active Directory 메인 페이지')
st.markdown(f"성공적으로 로그인했습니다.\n\n현재 로그인한 사용자: {username}")
tls_configuration = Tls(validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1_2)
server = Server(server, use_ssl=True, get_info=ALL, tls=tls_configuration)
conn = Connection(server, user=username, password=password)
if conn.bind():
#search_base = 'dc=gsoft,dc=local'
search_base = baseDN
search_filter = f'(UserPrincipalName={username})'
conn.search(search_base, search_filter, attributes=['displayName', 'description'])
if conn.entries:
entry = conn.entries[0]
st.write(f"displayname : {entry.displayName.value}")
st.write(f"description : {entry.description.value}")
if st.button("비밀번호 변경"):
st.session_state['page'] = 'change_password'
st.rerun()
change_password_page.py: 비밀번호 변경 페이지
import ssl
from ldap3 import Server, Connection, ALL, Tls
import streamlit as st
def change_password_page(server, username, baseDN):
if st.button("이전"):
st.session_state['page'] = 'main'
st.rerun()
st.title('비밀번호 변경 페이지')
old_password = st.text_input("현재 비밀번호", type='password')
new_password = st.text_input("새 비밀번호", type='password')
confirm_password = st.text_input("새 비밀번호 확인", type='password')
if st.button("비밀번호 변경"):
if new_password != confirm_password:
st.error("새 비밀번호와 확인 비밀번호가 일치하지 않습니다.")
else:
try:
tls_configuration = Tls(validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1_2)
server = Server(server, use_ssl=True, get_info=ALL, tls=tls_configuration)
conn = Connection(server, user=username, password=old_password)
if not conn.bind():
st.error("현재 비밀번호가 잘못되었습니다.")
else:
#search_base = 'dc=gsoft,dc=local'
search_base = baseDN
search_filter = f'(UserPrincipalName={username})'
conn.search(search_base, search_filter, attributes=['displayName'])
if conn.entries:
user_dn = conn.entries[0].entry_dn
conn.extend.microsoft.modify_password(user_dn, new_password, old_password)
if conn.result['description'] == 'success':
st.success("비밀번호가 성공적으로 변경되었습니다.")
st.session_state['password'] = new_password
else:
st.error(f"비밀번호 변경 실패: {conn.result}")
except Exception as e:
st.error(f"비밀번호 변경 중 오류 발생: {str(e)}")
app.py: 메인 어플리케이션 실행 파일
import streamlit as st
from login_page import login_page
from main_page import main_page
from change_password_page import change_password_page
# 세션 상태 초기화
if 'authenticated' not in st.session_state:
st.session_state['authenticated'] = False
st.session_state['server'] = None
st.session_state['username'] = None
st.session_state['password'] = None
st.session_state['baseDN'] = None
# 로그인 상태에 따라 페이지 표시
if st.session_state['authenticated']:
if st.session_state['page'] == 'main':
main_page(st.session_state['server'], st.session_state['username'], st.session_state['password'], st.session_state['baseDN'])
elif st.session_state['page'] == 'change_password':
change_password_page(st.session_state['server'], st.session_state['username'], st.session_state['baseDN'])
else:
login_page()
Streamlit run app.py
실행을 하면 기존과 같이 동일하게 실행 됨을 확인 할 수 있다.
댓글