之前做过的项目用过几种不同的加密方式,总结下
文章目录
Python
1. 使用werkzeug.security.generate_password_hash
information新闻系统
# 注册用户
# 请求路径: /passport/register
# 请求方式: POST
# 请求参数: mobile, sms_code,password
# 返回值: errno, errmsg
@passport_bp.route('/register', methods=['POST'])
def register():
# 1.获取参数
dict_data = request.json
mobile = dict_data.get('mobile')
sms_code = dict_data.get('sms_code')
password = dict_data.get('password')
# 2.校验参数
if not all([mobile, sms_code, password]):
return jsonify(errno=RET.PARAMERR, errmsg='参数不全')
# 3.手机号作为key取出redis中的短信验证码
try:
redis_sms_code = redis_store.get('sms_code:%s'%mobile)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg='短信验证码取出失败')
# 4.判断短信验证码是否过期
if not redis_sms_code:
return jsonify(errno=RET.NODATA, errmsg='短信验证码已经过期')
# 5.判断验证码是否正确
if sms_code != redis_sms_code:
return jsonify(errno=RET.DATAERR, errmsg='短信验证码填写错误')
# 6.删除短信验证码
try:
redis_store.delete('sms_code:%s'%mobile)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg='短信验证码删除失败')
# 7. 创建用户对象
user = User()
# 8. 设置用户对象属性
user.nick_name = mobile
user.password = password
user.mobile = mobile
user.signature = '改用户很懒,什么都没写'
# 9. 保存用户到数据库
try:
db.session.add(user)
db.session.commit()
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
return jsonify(errno=RET.DBERR, errmsg='用户注册失败')
# 10. 返回响应
return jsonify(errno=RET.OK, errmsg='注册成功')
class User(BaseModel, db.Model):
"""用户"""
__tablename__ = "info_user"
id = db.Column(db.Integer, primary_key=True) # 用户编号
nick_name = db.Column(db.String(32), unique=True, nullable=False) # 用户昵称
password_hash = db.Column(db.String(128), nullable=False) # 加密的密码
mobile = db.Column(db.String(11), unique=True, nullable=False) # 手机号
avatar_url = db.Column(db.String(256)) # 用户头像路径
last_login = db.Column(db.DateTime, default=datetime.now) # 最后一次登录时间
is_admin = db.Column(db.Boolean, default=False)
signature = db.Column(db.String(512)) # 用户签名
gender = db.Column( # 订单的状态
db.Enum(
"MAN", # 男
"WOMAN" # 女
),
default="MAN")
# 当前用户收藏的所有新闻
collection_news = db.relationship("News", secondary=tb_user_collection, lazy="dynamic") # 用户收藏的新闻
# 用户所有的粉丝,添加了反向引用followed,代表用户都关注了哪些人
followers = db.relationship('User',
secondary=tb_user_follows,
primaryjoin=id == tb_user_follows.c.followed_id,
secondaryjoin=id == tb_user_follows.c.follower_id,
backref=db.backref('followed', lazy='dynamic'),
lazy='dynamic')
# 当前用户所发布的新闻
news_list = db.relationship('News', backref='user', lazy='dynamic')
@property
def password(self):
raise AttributeError("当前属性不可读")
@password.setter
def password(self, value):
self.password_hash = generate_password_hash(value)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def to_dict(self):
resp_dict = {
"id": self.id,
"nick_name": self.nick_name,
"avatar_url": constants.QINIU_DOMIN_PREFIX + self.avatar_url if self.avatar_url else "",
"mobile": self.mobile,
"gender": self.gender if self.gender else "MAN",
"signature": self.signature if self.signature else "",
"followers_count": self.followers.count(),
"news_count": self.news_list.count()
}
return resp_dict
def to_admin_dict(self):
resp_dict = {
"id": self.id,
"nick_name": self.nick_name,
"mobile": self.mobile,
"register": self.create_time.strftime("%Y-%m-%d %H:%M:%S"),
"last_login": self.last_login.strftime("%Y-%m-%d %H:%M:%S"),
}
return resp_dict
titan
def sign_in(self, password: str) -> str:
"""
用户登录
:param password:
:return:
"""
if self.is_anonymous:
raise exceptions.NotFound(message='用户不存在')
# 密码校检
check_pw = self.user.validate_password(password)
if not check_pw:
raise exceptions.InvalidArgument(message='密码不正确')
# 更新登录时间
now = time.time()
self.user.login_at = now
self.user_repo.save(self.user)
token = encode_token(role=self.user.role, id=self.user.id, login_at=self.user.login_at,
env=current_app.config['ENV']).decode()
# 从登出用户缓存列表中删除该用户
if redis.sismember(SignOutUserListKey, self.user.id):
redis.srem(SignOutUserListKey, self.user.id)
auth_token = 'JWT ' + token
return auth_token
model.py
from typing import List, Optional
from sqlalchemy import BIGINT, VARCHAR, SMALLINT
from sqlalchemy import and_, or_
from sqlalchemy import distinct
from werkzeug.security import generate_password_hash, check_password_hash
class User(BaseObject, psql.Model):
"""
用户表
"""
__tablename__ = 'st_user'
# common fields
id = psql.Column(VARCHAR(32), autoincrement=False, primary_key=True)
created_at = psql.Column(BIGINT)
updated_at = psql.Column(BIGINT)
deleted_at = psql.Column(BIGINT) # 如果不为None则该数据已删除
# flexible information
login_at = psql.Column(BIGINT) # 最近登录时间
name = psql.Column(VARCHAR(128)) # 用户姓名
phone = psql.Column(VARCHAR(16), unique=True, index=True) # 用户注册手机号
password = psql.Column(VARCHAR(128))
avatar = psql.Column(VARCHAR(256)) # 用户头像URL
role = psql.Column(SMALLINT) # 用户角色
extended_role = psql.Column(SMALLINT)
# store index, i.e. __table_args__ = (Index("id_idx", id), Index("id_phone_idx", id, phone))
__table_args__ = ()
__fields = ('deleted_at', 'password')
def __init__(self, phone, password, **kwargs):
super().__init__(**kwargs)
self.phone = phone
self.password = self.set_password(password)
@staticmethod
def set_password(password):
return generate_password_hash(password)
def validate_password(self, password):
return check_password_hash(self.password, password)
@staticmethod
def check_password(hash_, password): # remove when UserManager works
return check_password_hash(hash_, password)
2. 加盐salt
order 订餐系统
import hashlib
import base64
import random
import string
class UserService:
@staticmethod
def gene_auth_code(user_info):
"""生成授权码"""
m = hashlib.md5()
raw_str = "%s-%s-%s-%s" % (user_info.uid, user_info.login_name, user_info.login_pwd, user_info.login_salt)
m.update(raw_str.encode("utf-8"))
return m.hexdigest()
@staticmethod
def gene_pwd(pwd, salt):
"""密码检验"""
m = hashlib.md5()
raw_str = "%s-%s" % (base64.encodebytes(pwd.encode('utf-8')), salt)
m.update(raw_str.encode("utf-8"))
return m.hexdigest()
@staticmethod
def gene_salt(length=16):
keys = [random.choice((string.ascii_letters + string.digits)) for _ in range(length)]
return ("".join(keys))
@route_user.route("/login", methods=["GET", "POST"])
def login():
if request.method == "GET":
return ops_render("user/login.html")
resp = {'code': 200, 'msg': '登陆成功', 'data': {}}
req = request.values
login_name = req['login_name'] if 'login_name' in req else ''
login_pwd = req['login_pwd'] if 'login_pwd' in req else ''
if login_name is None or len(login_name) < 1:
resp['code'] = -1
resp['msg'] = "请输入正确的用户名!"
return jsonify(resp)
if login_pwd is None or len(login_pwd) < 1:
resp['code'] = -1
resp['msg'] = "请输入正确的密码!"
return jsonify(resp)
user_info = User.query.filter_by(login_name=login_name).first()
if not user_info:
resp['code'] = -1
resp['msg'] = "请输入正确的用户名和密码!"
return jsonify(resp)
if user_info.login_pwd != UserService.gene_pwd(login_pwd, user_info.login_salt): # 登录密码与加密key
resp['code'] = -1
resp['msg'] = "请输入正确的用户名和密码!"
return jsonify(resp)
if user_info.status != 1:
resp['code'] = -1
resp['msg'] = "账号已被禁用,请联系管理员!"
return jsonify(resp)
response = make_response(json.dumps(resp))
response.set_cookie(app.config['AUTH_COOKIE_NAME'],
"%s#%s" % (UserService.gene_auth_code(user_info), user_info.uid))
return response
Go
1. EncoderSha256
gin_resaurant云餐厅
//用户登录
func (ms *MemberService) Login(name string, password string) *model.Member {
//1、使用用户名 + 密码 查询用户信息 如果存在用户 直接返回
md := dao.MemberDao{tool.DbEngine}
member := md.Query(name, password)
if member.Id != 0 {
return member
}
//2、用户信息不存在,作为新用户保存到数据库中
user := model.Member{}
user.UserName = name
user.Password = tool.EncoderSha256(password)
user.RegisterTime = time.Now().Unix()
result := md.InsertMember(user)
user.Id = result
return &user
}
package tool
import (
"crypto/sha256"
"encoding/hex"
"crypto/md5"
"io"
"encoding/base64"
"fmt"
)
func EncoderSha256(data string) string {
h := sha256.New()
h.Write([]byte(data))
sum := h.Sum(nil)
//由于是十六进制表示,因此需要转换
s := hex.EncodeToString(sum)
return string(s)
}
func Md5(data string) string {
w := md5.New()
io.WriteString(w, data)
bydate := w.Sum(nil)
result := fmt.Sprintf("%x", bydate)
return result
}
func Base64Encode(data string) string {
return base64.StdEncoding.EncodeToString([]byte(data))
}
func Base64Decode(data string) ([]byte, error) {
return base64.StdEncoding.DecodeString(data)
}
2. ScryptPw
ginblog博客系统
package model
import (
"encoding/base64"
"ginblog/utils/errmsg"
"github.com/jinzhu/gorm"
"golang.org/x/crypto/scrypt"
"log"
)
type User struct {
gorm.Model
Username string `gorm:"type:varchar(20);not null " json:"username" validate:"required,min=4,max=12" label:"用户名"`
Password string `gorm:"type:varchar(20);not null" json:"password" validate:"required,min=6,max=20" label:"密码"`
Role int `gorm:"type:int;DEFAULT:2" json:"role" validate:"required,gte=2" label:"角色码"`
}
// 新增用户
func CreateUser(data *User) int {
//data.Password = ScryptPw(data.Password)
err := db.Create(&data).Error
if err != nil {
return errmsg.ERROR // 500
}
return errmsg.SUCCSE
}
// 密码加密
func (u *User) BeforeSave() {
u.Password = ScryptPw(u.Password)
}
func ScryptPw(password string) string {
const KeyLen = 10
salt := make([]byte, 8)
salt = []byte{12, 32, 4, 6, 66, 22, 222, 11}
HashPw, err := scrypt.Key([]byte(password), salt, 16384, 8, 1, KeyLen)
if err != nil {
log.Fatal(err)
}
fpw := base64.StdEncoding.EncodeToString(HashPw)
return fpw
}
3. bcrypt.GenerateFromPassword
package model
import (
"os"
"time"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/jinzhu/gorm"
"golang.org/x/crypto/bcrypt"
)
// User 用户模型
type User struct {
gorm.Model
UserName string
PasswordDigest string
Nickname string
Status string
Avatar string `gorm:"size:1000"`
Sex string
Birthday time.Time
Sign string
Upcnt uint
}
const (
// PassWordCost 密码加密难度
PassWordCost = 12
// Active 激活用户
Active string = "active"
// Inactive 未激活用户
Inactive string = "inactive"
// Suspend 被封禁用户
Suspend string = "suspend"
)
// SetPassword 设置密码
func (user *User) SetPassword(password string) error {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), PassWordCost)
if err != nil {
return err
}
user.PasswordDigest = string(bytes)
return nil
}
// CheckPassword 校验密码
func (user *User) CheckPassword(password string) bool {
err := bcrypt.CompareHashAndPassword([]byte(user.PasswordDigest), []byte(password))
return err == nil
}
cookie加密(AesEncrypt)
func (u *UserController) PostLogin() mvc.Response {
// 由于数据量少,直接通过上下文获取表单中的数据
userName := u.Ctx.FormValue("userName")
password := u.Ctx.FormValue("password")
_, isOK := u.UserService.IsPwdSussess(userName, password)
if !isOK {
golog.Error("登陆失败,用户名或密码不正确!")
return mvc.Response{Path: "/user/login"}
}
user, err := u.UserService.GetUserByName(userName)
if err != nil {
golog.Error("获取用户信息失败!")
return mvc.Response{Path: "/user/login"}
}
// 将用户id写入Cookie
tool.GlobalCookie(u.Ctx, "uid", strconv.FormatInt(user.ID, 10), 60*60*24)
golog.Debug("cookie设置成功!", u.Ctx.GetCookie("uid"))
// 加uid加密
uidString, err := encrypt.EnPwdCode([]byte(strconv.FormatInt(user.ID, 10)))
if err != nil {
golog.Error("加密失败!", err)
return mvc.Response{Path: "/user/login"}
}
// 将用户加密信息写入Cookie
tool.GlobalCookie(u.Ctx, "sign", uidString, 60*60*24)
golog.Debug("登陆成功!")
return mvc.Response{Path: "/product/detail"}
}
package encrypt
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"errors"
)
//高级加密标准 (Advanced Encryption Standard)AES
//16,24,32位字符串的话,分别对应AES-128,AES-192,AES-256加密方法
//key不能泄漏
var PwdKey=[]byte("DIS**#KKKDJJSKDI")
//PKCS7 填充模式
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
//填充的反向操作,删除填充字符串
func PKCS7UnPadding(origData []byte) ([]byte, error) {
length := len(origData)
if length == 0 {
return nil, errors.New("加密字符串错误")
} else {
padding := int(origData[length-1])
return origData[:(length - padding)], nil
}
}
//实现解密
func AesDeCrypt(cypted []byte, key []byte) ([]byte, error) {
//创建加密算法实例
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
origData := make([]byte, len(cypted))
//这个函数也可以用来解密
blockMode.CryptBlocks(origData, cypted)
//去除填充字符串
origData, err = PKCS7UnPadding(origData)
if err != nil {
return nil, err
}
return origData, nil
}
//实现加密
func AesEncrypt(origData []byte, key []byte) ([]byte, error) {
//创建加密算法实例
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
//获取块大小
blockSize := block.BlockSize()
//对数据进行填充,让数据长度满足需求
origData = PKCS7Padding(origData, blockSize)
//采用AES加密方法中CBC加密模式
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
crypted := make([]byte, len(origData))
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
//加密base64
func EnPwdCode(pwd []byte) (string, error) {
result, err := AesEncrypt(pwd, PwdKey)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(result), err
}
func DePwdCode(pwd string) ([]byte, error) {
pwdByte, err := base64.StdEncoding.DecodeString(pwd)
if err != nil {
return nil, err
}
//执行AES解密
return AesDeCrypt(pwdByte, PwdKey)
}
验证cookie
func CheckUserInfo (r *http.Request) error {
uidCookie, err := r.Cookie("uid")
if err != nil {
return errors.New("用户uid cookie 获取失败!")
}
//获取用户加密串
signCookie, err := r.Cookie("sign")
if err != nil {
return errors.New("用户加密串 cookie 获取失败!")
}
signStr, err := url.QueryUnescape(signCookie.Value)
if err != nil {
return errors.New("url decode 失败")
}
signByte, err := encrypt.DePwdCode(signStr)
if err != nil {
return errors.New("加密串被篡改")
}
if checkInfo(uidCookie.Value , string(signByte)) {
return nil
}
return errors.New("身份校验失败")
}
//统一验证拦截器,每个接口都需要提前验证
func Auth(w http.ResponseWriter, r *http.Request) error {
err := CheckUserInfo(r)
if err != nil {
return errors.New("验证失败")
}
return nil
}
对称加密与非对称加密
一:什么是对称加密?
在对称加密算法中,加密和解密使用的是同一把钥匙,即:使用相同的密匙对同一密码进行加密和解密;
加密过程如下:
例如 jwt.SigningMethodHS256 对称加密
优点:算法简单,加密解密容易,效率高,执行快。
缺点:相对来说不算特别安全,只有一把钥匙,密文如果被拦截,且密钥也被劫持,那么,信息很容易被破译。
二:什么是对称加密?
非对称加密是使用不同的密钥进行加密和解密。
非对称加密有两个钥匙,及公钥(Public Key)和私钥(Private Key)。公钥和私钥是成对的存在,如果对原文使用公钥加密,则只能使用对应的私钥才能解密;因为加密和解密使用的不是同一把密钥,所以这种算法称之为非对称加密算法。