源码地址:https://github.com/FFlask/search_db
1、需求分析
N个数据库,依次模糊查询后返回结果,汇总后展示到界面上
数据库是保存在本地数据库中,并在后台界面动态的添加到查询系统中
为了保证安全,加个登陆,但不开放注册,统一在后台界面添加新用户
用户分为管理员和普通用户,管理员可以添加普通用户
单一IP暴力破解登陆的问题使用Nginx+验证码(暂未实现)来解决
2、数据库设计
共需要三张表,用户表和权限表,数据库管理表(用于保存需要查询的数据库)
3、框架选择
由于最近在学习Flask框架,本项目采用Flask框架和其配套模块
前端使用Bootstrap框架
由于功能简单(代码500行内),就所有代码就写在一个文件上了
4、具体功能实现
4.1 实现说明
已实现功能:登陆,汇总查询,数据表的增删改查,权限控制,普通用户的增删改查
未实现功能:验证码
系统的难点:数据表和本地数据库表的动态关联,使用了元类,通过字符串找类,动态创建变量名
初始化:初始化创建表的时候应将元类创建模型的部分注释掉
4.2 代码实现
1 # -*- coding: UTF-8 -*- 2 from flask import Flask,render_template,url_for,redirect,request,flash,session,abort 3 from flask_sqlalchemy import SQLAlchemy 4 from flask_wtf import FlaskForm 5 from wtforms import StringField,PasswordField,SubmitField,SelectField,ValidationError 6 from wtforms.validators import Email,EqualTo,Length,DataRequired 7 from werkzeug.security import generate_password_hash,check_password_hash 8 from flask_login import LoginManager,UserMixin,login_required,login_user,logout_user,current_user 9 from functools import wraps 10 11 12 app = Flask(__name__) 13 login_manager = LoginManager() 14 #设置验证强度,以提供不同的安全等级防止用户会话遭篡改 15 #设为'strong' 时,Flask-Login 会记录客户端IP地址和浏览器的用户代理信息,如果发现异动就登出用户 16 login_manager.session_protection = 'strong' 17 #设置登陆失败后的跳转 18 login_manager.login_view = 'index' 19 20 21 class Config: 22 SECRET_KEY = '1a1@z2' 23 SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:root@127.0.0.1/world?charset=utf8' 24 25 #SQLALCHEMY_TRACK_MODIFICATIONS = True 26 @staticmethod 27 def init_app(app): 28 pass 29 30 app.config.from_object(Config) 31 db=SQLAlchemy(app) 32 33 #数据库模型 34 35 @login_manager.user_loader 36 def load_user(user_id): 37 return User.query.get(int(user_id)) 38 login_manager.init_app(app) 39 #用户表 40 class User(UserMixin,db.Model): 41 __tablename__ = 'user' 42 id = db.Column(db.Integer,primary_key=True,index=True) 43 username = db.Column(db.String(64),unique=True,index=True) 44 password_hash = db.Column(db.String(128)) 45 role_id = db.Column(db.Integer, db.ForeignKey('role.id')) 46 47 @property 48 def password(self): 49 raise AttributeError('password unread') 50 51 @password.setter 52 def password(self,password): 53 self.password_hash = generate_password_hash(password) 54 55 def verify_password(self,password): 56 return check_password_hash(self.password_hash,password) 57 58 #新增用户默认是普通用户权限 59 def __init__(self,*args,**kwargs): 60 super(User,self).__init__(*args,**kwargs) 61 if self.role is None: 62 if self.username == 'admin': 63 self.role = Role.query.filter_by(role_name='Admin').first() 64 else: 65 self.role = Role.query.filter_by(role_name='User').first() 66 67 def can(self,permissions): 68 return self.role is not None and (self.role.permissions & permissions) == permissions 69 70 def is_admin(self): 71 return self.can(Permissions.Admin) 72 73 def __repr__(self): 74 return '<User %r>'%(self.username) 75 76 77 #权限类 78 class Permissions: 79 Visit = 0x01 80 Read = 0x02 81 Write = 0x04 82 Manager = 0x08 83 Admin = 0xFF 84 85 #角色权限表 86 class Role(db.Model): 87 __tablename__ = 'role' 88 id = db.Column(db.Integer,primary_key=True,index=True) 89 role_name = db.Column(db.String(64),unique=True,index=True) 90 permissions = db.Column(db.Integer) 91 user = db.relationship('User',backref='role') 92 93 @staticmethod 94 def init_role(): 95 roles = { 96 'Visitor':Permissions.Visit, 97 'User':Permissions.Visit|Permissions.Read|Permissions.Write, 98 'Manager':Permissions.Visit|Permissions.Read|Permissions.Write|Permissions.Manager, 99 'Admin':Permissions.Admin 100 } 101 for role_name,role_permissions in roles.items(): 102 role = Role(role_name=role_name,permissions=role_permissions) 103 db.session.add(role) 104 db.session.commit() 105 106 def __repr__(self): 107 return '<Role %r>'%(self.role_name) 108 109 110 111 #数据库表 112 class DBTable(db.Model): 113 __tablename__ = 'db_table' 114 id = db.Column(db.Integer, primary_key=True, index=True) 115 table_name = db.Column(db.String(64), unique=True) 116 table_src = db.Column(db.String(64)) 117 def __repr__(self): 118 return 'db_table <%r>'%(self.table_name) 119 120 121 122 #动态创建数据库模型 123 table1s = DBTable.query.all() 124 #把字符串变成变量 125 createVar = locals() 126 for table1 in table1s: 127 #使用元类动态创建表中存储的表名 128 createVar[str(table1.table_name)] = type(str(table1.table_name),(db.Model,),{ 129 '__tablename__':table1.table_name, 130 'id':db.Column(db.Integer, primary_key=True, index=True), 131 'username':db.Column(db.String(64), unique=True,index=True), 132 'password':db.Column(db.String(64)), 133 'email':db.Column(db.String(64), unique=True,index=True), 134 }) 135 136 137 #表单类 138 #搜索框 139 class SearchForm(FlaskForm): 140 search = StringField(validators=[DataRequired()], 141 render_kw={'class':'form-control', 142 'size':'50', 143 'placeholder':'input search content'}) 144 kind = SelectField(choices=[ 145 ('username','username'),('email','email') 146 ],render_kw={'class':'form-control'}) 147 submmit = SubmitField('Search',render_kw={'class':'btn btn-info'}) 148 149 #登陆框 150 class LoginForm(FlaskForm): 151 username = StringField('Username', validators=[DataRequired(), Length(1, 64)], 152 render_kw={'class':'form-control','placeholder':'enter your username'}) 153 password = PasswordField('Password', validators=[DataRequired()], 154 render_kw={'class':'form-control','placeholder':'enter your password'}) 155 verify_code = StringField('CheckCode', 156 render_kw={'class': 'form-control', 'placeholder': 'zzzzzzzzz'}) 157 submmit = SubmitField('Login',render_kw={'class':'btn btn-info'}) 158 159 #新增数据库 160 class DBAddForm(FlaskForm): 161 table_name = StringField('table_name', validators=[DataRequired()], 162 render_kw={'class':'form-control','placeholder':'table_name'}) 163 table_src = StringField('table_src', validators=[DataRequired()], 164 render_kw={'class': 'form-control', 'placeholder': 'table_src'}) 165 submmit = SubmitField('Add',render_kw={'class':'btn btn-info'}) 166 167 #编辑数据库 168 class DBEditForm(FlaskForm): 169 table_name = StringField('table_name', validators=[DataRequired()], 170 render_kw={'class':'form-control','placeholder':'table_name'}) 171 table_src = StringField('table_src', validators=[DataRequired()], 172 render_kw={'class': 'form-control', 'placeholder': 'table_src'}) 173 submmit = SubmitField('Edit',render_kw={'class':'btn btn-info'}) 174 175 #新增用户 176 class UserAddForm(FlaskForm): 177 username = StringField('username', validators=[DataRequired()], 178 render_kw={'class':'form-control','placeholder':'username'}) 179 password = StringField('password', validators=[DataRequired()], 180 render_kw={'class': 'form-control', 'placeholder': 'password'}) 181 submmit = SubmitField('Add',render_kw={'class':'btn btn-info'}) 182 183 def validate_username(self,field): 184 if User.query.filter_by(username = field.data).first(): 185 raise ValidationError('username is repeat') 186 187 #修改用户信息 188 class UserEditForm(FlaskForm): 189 username = StringField('username', validators=[DataRequired()], 190 render_kw={'class':'form-control','readonly':'readonly'}) 191 new_password = StringField('new_password', 192 render_kw={'class': 'form-control', 'placeholder': 'new password'}) 193 role = SelectField(coerce=int,render_kw={'class':'form-control'}) 194 submmit = SubmitField('Edit',render_kw={'class':'btn btn-info'}) 195 def __init__(self,*args,**kwargs): 196 super(UserEditForm,self).__init__(*args,**kwargs) 197 self.role.choices = [(role.id,role.role_name) for role in Role.query.order_by(Role.role_name).all() 198 if role.role_name=='Admin' or role.role_name == 'User'] 199 200 #权限控制装饰器 201 def permission_required(permission): 202 def decorator(func): 203 @wraps(func) 204 def decorated_function(*args, **kwargs): 205 if not current_user.can(permission): 206 abort(403) 207 return func(*args, **kwargs) 208 return decorated_function 209 return decorator 210 #具有admin权限 211 def is_admin(func): 212 return permission_required(Permissions.Admin)(func) 213 214 215 216 #业务逻辑 217 #初次运行时运行一下,创建admin账户 218 @app.route('/create_user') 219 def create_user(): 220 user1 = User.query.filter_by(username = 'admin').first() 221 if not user1: 222 user2 = User(username='admin',password='admin') 223 db.session.add(user2) 224 db.session.commit() 225 return 'ok' 226 227 #测试 228 @app.route('/test') 229 def test(): 230 return 'test' 231 232 #登陆页面 233 @app.route('/',methods=['GET','POST']) 234 def index(): 235 login_form = LoginForm() 236 if current_user.is_authenticated: 237 print(current_user.username) 238 if login_form.validate_on_submit(): 239 user1 = User.query.filter_by(username = login_form.username.data).first() 240 if user1 and user1.verify_password(login_form.password.data): 241 login_user(user1) 242 return redirect(request.args.get('next') or url_for('search_db')) 243 else: 244 flash('username or password error') 245 return redirect(url_for('index')) 246 return render_template('index.html',login_form=login_form) 247 248 @app.route('/logout') 249 @login_required 250 def logout(): 251 logout_user() 252 return redirect(url_for('index')) 253 254 #搜索页面 255 @app.route('/search_db',methods=['GET','POST']) 256 @login_required 257 def search_db(): 258 search_form = SearchForm() 259 ip = request.remote_addr 260 results = {} 261 if search_form.validate_on_submit(): 262 search_item = search_form.kind.data 263 for index,table1 in enumerate(DBTable.query.all()): 264 try: 265 #动态创建变量名 266 createVar[str(table1.table_name)+str(index)] = 267 globals()[table1.table_name].query.filter(getattr(globals()[table1.table_name],search_item) 268 .like('%'+'%s'%search_form.search.data+'%')).all() 269 if createVar[str(table1.table_name)+str(index)] is not None: 270 results.update({table1.table_src: createVar[str(table1.table_name)+str(index)]}) 271 except: 272 flash('Your db is not have table <%s>,Please update it!'%(str(table1.table_name))) 273 return render_template('search_db.html',search_form=search_form,results=results,ip=ip) 274 275 #数据库管理/查 276 @app.route('/admin_db/query') 277 @login_required 278 @is_admin 279 def admin_db_query(): 280 return render_template('admin_db_query.html', table1s = DBTable.query.all()) 281 282 #数据库管理/增 283 @app.route('/admin_db/add',methods=['POST','GET']) 284 @login_required 285 @is_admin 286 def admin_db_add(): 287 db_add_form = DBAddForm() 288 if db_add_form.validate_on_submit(): 289 new_table = DBTable( 290 table_name=db_add_form.table_name.data, 291 table_src=db_add_form.table_src.data, 292 ) 293 db.session.add(new_table) 294 db.session.commit() 295 return redirect(url_for('admin_db_query')) 296 return render_template('admin_db_add.html',db_add_form=db_add_form) 297 298 #数据库管理/改 299 @app.route('/admin_db/edit',methods=['POST','GET']) 300 @login_required 301 @is_admin 302 def admin_db_edit(): 303 edit_id = request.args.get('edit_id') 304 db_table1 = DBTable.query.filter_by(id=edit_id).first() 305 db_edit_form = DBEditForm() 306 if db_edit_form.validate_on_submit(): 307 db_table1.table_name = db_edit_form.table_name.data 308 db_table1.table_src = db_edit_form.table_src.data 309 db.session.add(db_table1) 310 db.session.commit() 311 return redirect(url_for('admin_db_query')) 312 db_edit_form.table_name.data = db_table1.table_name 313 db_edit_form.table_src.data = db_table1.table_src 314 return render_template('admin_db_edit.html',db_edit_form=db_edit_form,db_table1=db_table1) 315 316 #数据库管理/删 317 @app.route('/admin_db/delete') 318 @login_required 319 @is_admin 320 def admin_db_delete(): 321 delete_id = request.args.get('delete_id') 322 db_table1 = DBTable.query.filter_by(id=delete_id).first() 323 db.session.delete(db_table1) 324 db.session.commit() 325 return redirect(url_for('admin_db_query')) 326 327 328 #用户管理/查 329 @app.route('/admin_user/query',methods=['POST','GET']) 330 @login_required 331 @is_admin 332 def admin_user_query(): 333 return render_template('admin_user_query.html',table1s=User.query.all()) 334 335 #用户管理/增 336 @app.route('/admin_user/add',methods=['POST','GET']) 337 @login_required 338 @is_admin 339 def admin_user_add(): 340 user_add_form = UserAddForm() 341 if user_add_form.validate_on_submit(): 342 new_user = User( 343 username=user_add_form.username.data, 344 password=user_add_form.password.data 345 ) 346 db.session.add(new_user) 347 db.session.commit() 348 return redirect(url_for('admin_user_query')) 349 return render_template('admin_user_add.html',user_add_form=user_add_form) 350 351 #用户管理/改 352 @app.route('/admin_user/edit',methods=['POST','GET']) 353 @login_required 354 @is_admin 355 def admin_user_edit(): 356 edit_id = request.args.get('edit_id') 357 user1 = User.query.filter_by(id=edit_id).first() 358 user_edit_form = UserEditForm() 359 if user_edit_form.validate_on_submit(): 360 user1.username = user_edit_form.username.data 361 user1.role_id = user_edit_form.role.data 362 if user_edit_form.new_password.data: 363 user1.password = user_edit_form.new_password.data 364 db.session.add(user1) 365 db.session.commit() 366 return redirect(url_for('admin_user_query')) 367 user_edit_form.username.data = user1.username 368 user_edit_form.role.data = user1.role_id 369 return render_template('admin_user_edit.html',user_edit_form=user_edit_form,user1=user1) 370 371 #用户管理/删 372 @app.route('/admin_user/delete',methods=['POST','GET']) 373 @login_required 374 @is_admin 375 def admin_user_delete(): 376 delete_id = request.args.get('delete_id') 377 user1 = User.query.filter_by(id=delete_id).first() 378 db.session.delete(user1) 379 db.session.commit() 380 return redirect(url_for('admin_user_query')) 381 382 383 if __name__ == '__main__': 384 app.run(host="0.0.0.0", port=5000)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>首页</title> 6 <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> 7 <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script> 8 <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> 9 </head> 10 <body> 11 <div class="col-sm-6 col-sm-offset-3"> 12 <h2>登陆</h2><br> 13 <form method="POST" action="{{ url_for('index') }}" > 14 {{ login_form.hidden_tag() }} 15 {{ login_form.username }}<br> 16 {{ login_form.password }}<br> 17 {{ login_form.submmit }} 18 </form> 19 <div> 20 {% for msg in get_flashed_messages() %} 21 {{ msg }} 22 {% endfor %} 23 </div> 24 </div> 25 26 </body> 27 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>搜索</title> 6 <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> 7 <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script> 8 <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> 9 </head> 10 <body> 11 <div class="col-sm-6 col-sm-offset-3"> 12 <h2>查询,查询,查询!</h2> 13 <form method="POST" action="{{ url_for('search_db') }}" class="form-inline" > 14 {{ search_form.hidden_tag() }} 15 {{ search_form.search }} 16 {{ search_form.kind }} 17 {{ search_form.submmit }} 18 </form> 19 20 <br> 21 {% for msg in get_flashed_messages() %} 22 <strong style="color: red">{{ msg }}</strong> 23 {% endfor %} 24 <hr> 25 <table border="1" class="table table-bordered"> 26 <thead> 27 <tr class="info"> 28 <td><strong>来源</strong></td> 29 <td><strong>用户</strong></td> 30 <td><strong>密码</strong></td> 31 <td><strong>邮箱</strong></td> 32 </tr> 33 </thead> 34 {% for result_key,result_value in results.items() %} 35 {% for result in result_value %} 36 <tr> 37 <td>{{ result_key }}</td> 38 <td>{{ result.username }}</td> 39 <td>{{ result.password }}</td> 40 <td>{{ result.email }}</td> 41 </tr> 42 {% endfor %} 43 {% endfor %} 44 </table> 45 </div> 46 <div class="col-sm-2"> 47 <a href="{{ url_for('index') }}">logout</a> 48 {% if current_user.username == 'admin' %} 49 <a href="{{ url_for('admin_db_query') }}">后台</a> 50 {% endif %} 51 <br>欢迎{{ current_user.username }}<br> 52 你的IP是:<{{ ip }}><br> 53 不要乱搞呦! 54 </div> 55 </body> 56 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>后台管理</title> 6 <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> 7 <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script> 8 <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> 9 </head> 10 <body> 11 <div class="col-sm-6 col-sm-offset-3"> 12 <ul class="nav nav-tabs nav-justified"> 13 <li role="presentation" class="active"><a href="#">数据库管理</a></li> 14 <li role="presentation"><a href="{{ url_for('admin_user_query') }}">用户管理</a></li> 15 <li role="presentation"><a href="{{ url_for('search_db') }}">返回查询</a></li> 16 </ul> 17 <ul class="nav nav-pills nav-justified"> 18 <li role="presentation" ><a href="{{ url_for('admin_db_query') }}">查</a></li> 19 <li role="presentation" class="active"><a href="{{ url_for('admin_db_add') }}">增</a></li> 20 <li role="presentation"><a href="#">改</a></li> 21 <li role="presentation"><a href="#">删</a></li> 22 </ul> 23 <hr> 24 <div class="jumbotron"> 25 <h4>新增数据库说明</h4> 26 <ul> 27 <li>本地数据库名必须为search_db</li> 28 <li>新增表名必须与数据库中表名完全一致</li> 29 <li>列名至少要包含username,password,email</li> 30 </ul> 31 </div> 32 <div class="col-sm-10 col-sm-offset-1"> 33 <form method="POST" action="{{ url_for('admin_db_add') }}" > 34 {{ db_add_form.hidden_tag() }} 35 {{ db_add_form.table_name }}<br> 36 {{ db_add_form.table_src }}<br> 37 {{ db_add_form.submmit }} 38 </form> 39 </div> 40 </div> 41 </body> 42 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>后台管理</title> 6 <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> 7 <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script> 8 <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> 9 </head> 10 <body> 11 <div class="col-sm-6 col-sm-offset-3"> 12 <ul class="nav nav-tabs nav-justified"> 13 <li role="presentation" class="active"><a href="#">数据库管理</a></li> 14 <li role="presentation"><a href="#">用户管理</a></li> 15 <li role="presentation"><a href="{{ url_for('search_db') }}">返回查询</a></li> 16 </ul> 17 <ul class="nav nav-pills nav-justified"> 18 <li role="presentation" ><a href="{{ url_for('admin_db_query') }}">查</a></li> 19 <li role="presentation" ><a href="{{ url_for('admin_db_add') }}">增</a></li> 20 <li role="presentation" class="active"><a href="#">改</a></li> 21 <li role="presentation"><a href="#">删</a></li> 22 </ul> 23 <hr> 24 <div class="jumbotron"> 25 <h4>修改数据库说明</h4> 26 <ul> 27 <li>本地数据库名必须为search_db</li> 28 <li>新增表名必须与数据库中表名完全一致</li> 29 <li>列名至少要包含username,password,email</li> 30 </ul> 31 </div> 32 <div class="col-sm-10 col-sm-offset-1"> 33 <form method="POST" action="{{ url_for('admin_db_edit',edit_id = db_table1.id) }}" > 34 {{ db_edit_form.hidden_tag() }} 35 {{ db_edit_form.table_name }}<br> 36 {{ db_edit_form.table_src }}<br> 37 {{ db_edit_form.submmit }} 38 </form> 39 </div> 40 </div> 41 </body> 42 </html>
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>后台管理</title> 6 <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> 7 <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script> 8 <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> 9 </head> 10 <body> 11 <div class="col-sm-6 col-sm-offset-3"> 12 <ul class="nav nav-tabs nav-justified"> 13 <li role="presentation" class="active"><a href="#">数据库管理</a></li> 14 <li role="presentation"><a href="{{ url_for('admin_user_query') }}">用户管理</a></li> 15 <li role="presentation"><a href="{{ url_for('search_db') }}">返回查询</a></li> 16 </ul> 17 <ul class="nav nav-pills nav-justified"> 18 <li role="presentation" class="active"><a href="{{ url_for('admin_db_query') }}">查</a></li> 19 <li role="presentation"><a href="{{ url_for('admin_db_add') }}">增</a></li> 20 <li role="presentation"><a href="#">改</a></li> 21 <li role="presentation"><a href="#">删</a></li> 22 </ul> 23 <hr> 24 <div class="col-sm-10 col-sm-offset-1"> 25 <table border="1" class="table table-bordered"> 26 <thead> 27 <tr class="info"> 28 <td>id</td> 29 <td>表名</td> 30 <td>来源</td> 31 <td>操作</td> 32 </tr> 33 </thead> 34 {% for table in table1s %} 35 <tr> 36 <td>{{ table.id }}</td> 37 <td>{{ table.table_name }}</td> 38 <td>{{ table.table_src }}</td> 39 <td><a href="{{ url_for('admin_db_edit',edit_id = table.id) }}">修改</a>|<a href="{{ url_for('admin_db_delete',delete_id = table.id) }}">删除</a></td> 40 </tr> 41 {% endfor %} 42 </table> 43 </div> 44 </div> 45 </body> 46 </html>
4.3 界面展示
5、经验总结
所有后端代码都写一个文件还是有点乱,下次还是分开
用户登陆,权限控制应当制作成一个模块,以后每次复制粘贴就行了