本文目的主要是想解决加密登录的问题,在注册时就把密码hash后保存在数据库中。加密的方案有很多,我要求不高,就选择了SHA256加盐。后端在接收到登录请求时在form中加了一个隐藏的salt,前端使用sha256.js先对密码做hash,加上salt做一次hash后提交。后端使用hashlib,将数据库中的已hash的密码值与salt相加再做一次hash,结果与前端提交上来的值做比较。
本文使用python+flask
后端代码摘段如下(数据库中的密码是经过hash了,将它加盐后再hash一次,就可以与前端送来的password判断了。盐值的产生是在响应‘login’时加入到form中):
import hashlib
from wtforms import StringField, PasswordField, SubmitField, HiddenField
class LoginForm():
salt = HiddenField('salt')
name = StringField('姓名', validators=[DataRequired()])
password = PasswordField('密码', validators=[DataRequired()])
submit = SubmitField('提交')
@app.route('/login', methods=['GET', 'POST'])
def login():
def do_get(form):
return render_template('login.html', form=form)
def do_post(form):
user = User.query.filter_by(name=form.name.data).first()
if user is None or get_hash(user.password + form.salt.data) != form.password.data: # 将数据库中password值加盐后hash,就可以与提交上来的form.password中的值做比较了。
session['logined'] = False
flash('帐号或密码错误,请重新登录')
return render_template('login.html', form=form)
else:
flash('登录成功!')
session['logined'] = True
session['name'] = form.name.data
return redirect(url_for('index'))
login_form = LoginForm()
if request.method == 'GET':
login_form.salt.data = uuid.uuid4().hex # 产生盐值
return do_get(login_form)
else:
return do_post(login_form)
def get_hash(s):
hash = hashlib.sha256()
hash.update(s.encode('utf-8'))
return hash.hexdigest()
前端regist.html(关键在后边的提交的script代码,将密码hash后再提交,这样子数据库中保存的密码是经过hash的,但未加盐。加盐这一步放在登录时使用。):
{% extends 'base.html' %}
{% block title %}注册 - {% endblock %}
{% block content %}
{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
<button class="close" data-dismiss="alert">×</button>
{
{ message }}
</div>
{% endfor %}
<div class="col-md-12 text-center">
<form class="form-horizontal" role="form" id="regform" action="./register" method="post">
<div class="form-group">
<div><h3>注册信息</h3></div><br>
<label for="name">姓       名</label>
{
{ form.name }}<br><br>
<label for="password">密       码</label>
{
{ form.password }}<br><br>
<label for="password2">{
{ form.password2.label }}</label>
{
{ form.password2 }}<br><br>
<label for="phonenum">{
{ form.phonenum.label }}</label>
{
{ form.phonenum }}<br><br>
<label for="unit">{
{ form.unit.label }}</label>
{
{ form.unit }}<br><br>
<span class="col-md-2 col-md-offset-4 col-xs-6">
<input type="button" class="form-control btn btn-default" onclick="register()" value= "提交">
</span>
<span class="col-md-2 col-xs-6">
<input type="reset" class="form-control btn btn-default" value= "复位">
</span>
</div>
</form>
</div>
{% endblock %}
{% block script %}
{
{ super() }}
<script type="text/javascript" src="../static/sha256.js"></script>
<script>
function register() {
var regform = document.getElementById("regform");
if (regform.password.value != regform.password2.value){
alert("确认密码与密码不符合,请重新输入");
}
else{
regform.password.value = sha256_digest(regform.password.value); # 提交之前把password的值hash,这样子后端数据库中的password就是经过hash的密码
regform.submit();
}
}
</script>
{% endblock %}
前端的login.html(关键在后边的提交的script代码,将密码hash后,加盐再hash,然后再提交):
{% extends 'base.html' %}
{% block title %}登录 - {% endblock %}
{% block content %}
{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
<button class="close" data-dismiss="alert">×</button>
{
{ message }}
</div>
{% endfor %}
<div class="col-md-12 text-center">
<form id="login" class="form-horizontal" role="form" action="./login" method="post">
<div class="form-group">
<div><h3>用户登录</h3></div><br>
<!--{
{ form.hidden_tag() }}-->
{
{ form.salt }}
<label for="name" class="control-label">{
{ form.name.label }}</label>
{
{ form.name }}<br><br>
<label for="password" class="control-label">{
{ form.password.label }}</label>
{
{ form.password }}<br><br>
<span class="col-md-2 col-md-offset-4 col-xs-6">
<input type="button" class="form-control btn-default" value="提交" onclick="login()">
</span>
<span class="col-md-2 col-xs-6">
<input type="reset" class="form-control btn-default" value="复位">
</span>
</div>
</form>
</div>
{% endblock %}
{% block script %}
{
{ super() }}
<script type="text/javascript" src="../static/sha256.js"></script>
<script>
function login() {
var loginform = document.getElementById("login");
loginform.password.value = sha256_digest(sha256_digest(loginform.password.value)+loginform.salt.value); # 登录时,要将密码先hash一次(此值就跟数据库中的值是一样的了),加盐后又hash。
loginform.submit();
}
</script>
{% endblock %}