加密方式
方案1 使用Base64编码
最常用的就是Base64编码了,Base64不算是加密,只是把字符经过编码变成不可读一串文字。
如果你的项目对安全根本没有什么要求,你就可以使用编码的方式,简单省事。但是这个方式只是比“裸奔”好那么一点,可以防止大部分小白用户吧。
方案2 AES加密
后台和前台双方约定好key .进行加密和解密都是可以的。
方案3AES加密,密码随机生成
key 就公开出去了,就得吧key来回传递
方案4RSA 加密
公钥给服务器,私钥给客户端,这样就好很多了。 和aes 单个用一样
方案5 AES加密 + RSA结合
思考。
保障每次安全性。就相出了思路。
![](https://img.haomeiwen.com/i1309984/84d07d63e11fa9b5.png)
思路大体是这样的
https://www.cnblogs.com/wuyanzu/p/11874333.html
app 数据用AES 加密,加密的key 用RSA 在加密。。
给服务器 加密后data 和 key .
后台用RSA 在解密得到key
然后数据用key 使用AES 解密 获取正确的数据
案例过程
例如登录
![](https://img.haomeiwen.com/i1309984/6dfb30fb5204eed9.png)
我把 登录的信息数据加密了。
{"aesKey":"FuQsmp2bKJZex02Ud2qx+uCkfA2Nef5KjCEC+O4sIwoD+ecxzUGk57plYdHLPdAYzt545A50hCfSxCRYy4KRcofzvhVV+JVjmIibeZUHozmvCdAqsSpi+Kd+W7FSFNvfZIoJAnTF6G8+UykDzSimZcfQALuAVc//q1d4dPT8Auc=","data":"A12B4B2AC0338865777FF7FD2F80D4CC768EBAE136F9B3B9C5AB06EDDD5D68AC7EB465D5872527EFE0520D8FC839010E"}
然后获取数据
{
"code": 0,
"msg": "操作成功!",
"data": {
"data": "C269985D917F9C09E5B054B850914802834ABBFE0974A452C5C5B8E3344A727559A72B8D75C45972626CF7F1BA4ACA7D29CE7DE161466784CC31C7780B37BF4C976D898F019FC3F8BDB54C556E4690AC6762B4152FC72F1EDAF128831A73F10E3E130332A87479938B414D6F65DF30567AF9FD51E1F27DED1A612749AE79537CBACDE0ED4C3015D07820E40D841D502E43B149DD8FDCA98F2DC47998720E360340555CE85AF28E10E38A6BF4F728D7D47BD14DFEF5F7ED9661B10702FDF0C0E0C0C8FDF7D06646BA1C021D819BE27F56DB3443FEB55F9C66AB215288694D0794AAB642A617186B0278E17507212F15582A024241C88F02EA12A27DC584C3FC556FA541144CD7D8FAD1BB39DA56EE4ED302930178F257498E48210E8EF81569EE90815CD13871C082BDA62A47124A59FCDB8682A45DB0B04BE45081C7E90AA6F2B2D1D28C0E2112B393A99776D5974CF4A24E97F1EBD5754692074D329FD44EBAC763920B923DEC97D809AE72ACF97A2E",
"aesKey": "PV9eTaMQi3VJmjxkw9fdnAEJ+5UxHzGcc0SkIXiB6ShDnWcpZ/kTZjOzon2XHZYwKuMBE6QzaAJsMqHr40XMyJXU7uqITSAzY6fdyM/z35PFGV0W8uSMREaNc6qT22GyEJn5OFRcvL0HnLF/7hiHyTGqIwgUMxA2JxLW6swsONU="
}
}
数据公开了就key 。key 用RSA 加密,我们解密一下。
说明这哥俩 参数,都是加密之后的。。。。
解密data 都得解析出来,才能继续解密
这个过程是不可逆的,因为aes 的key 是随机的。。。
我们的RSA私钥和公钥并没有 公开出去。
android 端的实现
android 用okhttp 来实现
binding.btLogin.setOnClickListener {
val name = binding.etName.text.toString()
val pass = binding.etPass.text.toString()
val loginVo = LoginVo(name, pass)
// val toJson = GsonUtils.toJson(loginVo)
// val JSON = "application/json; charset=utf-8"
val url = "http://192.168.1.138:8089/SysUser/loginAndroid"
// val body = RequestBody.create(MediaType.parse(JSON), toJson)
val toJson = GsonUtils.toJson(loginVo)
println("加密前:$toJson")
val encrypt = SecurityUtil.encrypt(loginVo, SecurityUtil.publicKey)
println("加密后:$encrypt")
val body = FormBody.Builder()
// .add("name", name)
// .add("pass", pass)
.add("data", encrypt)
.build();
val okHttpClient = OkHttpClient()
val request: Request = Request.Builder()
.url(url)
.post(body)
.build()
val call: Call = okHttpClient.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call?, e: IOException?) {
Log.d(TAG, "onFailure: " + e?.message)
}
override fun onResponse(call: Call?, response: Response) {
val result = response.body()?.string()
Log.d(TAG, "onResponse: $result")
runOnUiThread {
if (!TextUtils.isEmpty(result)) {
println("获取的数据:$result")
val emptyBean =
GsonUtils.fromJson<EmptyBean>(result, EmptyBean::class.java)
if (emptyBean.code == 0) {
val encrypt1 =
SecurityUtil.decrypt(emptyBean.data.data, emptyBean.data.aesKey)
println("解密后数据:$encrypt1")
val fromJson =
GsonUtils.fromJson<UserInfo>(encrypt1, UserInfo::class.java)
println("解析后的数据:$fromJson")
}else{
println("错误信息" + emptyBean.msg)
}
}
}
}
})
}
打印
2021-11-04 11:02:17.131 19744-19744/com.compose.empty I/System.out: 加密前:{"name":"admin","pass":"123456"}
2021-11-04 11:02:17.138 19744-19744/com.compose.empty I/System.out: aes_key:R1690Mlqe5Yp02Gc
2021-11-04 11:02:17.142 19744-19744/com.compose.empty I/System.out: 加密后:{"aesKey":"phmZ1eI4ahqexiJFNeomkuPeHXHbpsUwz18Nn8MaqHt8g27042T8xH76j8ZfCaUJ9//Y4cxJ9LdxFyeY2njpRxDcNsK7pxpnpgeDcVjflLWc4MUj+t+4qwilDpcxVpnvfPUSL5Q60aawZYENdn4GyBw64ZKecVc7Wnp7rk8gn8A=","data":"BCA1A469864B968EC82287DF6D75284B652B2830D03F853A9C9A010E8EC92DFC239D834ABA70382AF6ED47CDC114196B"}
2021-11-04 11:02:17.249 19744-19744/com.compose.empty I/System.out: 获取的数据:{"code":0,"msg":"操作成功!","data":{"data":"06849C74EACA36F649D9724C52308DF34D097CC998055F93BCA3F814C6D31EF810B13BBDC6368705E7FD86B5D43DA97D3BB893E0D599A60C221AC5179D14D318F87556031C8DB6E0A7C2D0C1078A025FFCC8D44A319D1E21DA83DB241B6D83090D8754ED26E9E56BD8EBC746F33F0529D324672ECDB10A3FF3EFC1D1D4116AF60F5BC772FC1A43F00DF53B7ECDDAB29829F70648AADA1486F6D276712D960931C249C006BADF1E18A27567CAB7862DE80120434A84728EE23FDAAD7862CD301F95A9C5FE2BE73E53690213A04E2D31F9B6AE162E677B89455BEFD95BFE73E2003D0AA782FF6CDEAEDF490B610ADE86D6C3B9D9314FCE88E3B6F7C9BF809807EEE84E29CBAC89816692DBA1FDDA2FDB27C15A559BFD3A6EA0C34C7B94E77B38AB1F76DDCC01AEB6660FF0B0AB3198F32E256189A66AFE71A2E7509FD4D634FCD8F90A7A1846D31BB0C36BF206AA4DE48E04DBD4D1B72A318A97E778BE41E34206D392E0B496012E50977893CF462F043B","aesKey":"CUrSmqrAimIpLNB+V4hJ9LYveD287iwk+NHYqEPYplRyCFx4wZWl6Ba79n0sHR7ookRUJ4fO5QASKQS1Nn/mbvp/AG8Bce5umUrJdgbOl7lIeAXmjOeLHk3vR2PJmx3Jv8veJ3IuZyBliW2MqbJz4euzJXoBtL0DEiXR/NAAUl0="}}
2021-11-04 11:02:17.262 19744-19744/com.compose.empty I/System.out: 解密后数据:{"id":1,"account":"admin","password":"123456","nickName":"管理员","name":"管理员","avatar":"http://localhost:8089/admin/images/avatar.png","birthday":null,"sex":0,"email":null,"phone":null,"tel":null,"lastLoginIp":null,"lastLoginTime":null,"adminType":0,"status":0,"createTime":null,"createUser":null,"updateTime":null,"updateUser":null,"remark":null}
2021-11-04 11:02:17.265 19744-19744/com.compose.empty I/System.out: 解析后的数据:com.compose.empty.bean.UserInfo@d221a8b
body 里面走的就是加密之后的数据。。。
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
加密过程就是
![](https://img.haomeiwen.com/i1309984/b205ecf9a7d3985d.png)
这个是真正的对数据加密
String decode = AESUtil.aesEncrypt(dataString, keyAES);
下面还有一个加密就是 对key 加密了
String aesKey = Base64Utils.encode(RSAUtils.encryptData(keyAES.getBytes(), public_Key));
Base64 给服务器就行了。。
服务上给的数据进行 解密。。。。
![](https://img.haomeiwen.com/i1309984/50b55ef06666a83b.png)
这样就搞定了。
java 后台实现
后台也是这样做的
![](https://img.haomeiwen.com/i1309984/039aea50edbe00b6.png)
遇到问题是,加密之后app 加密后后台解析不了。
Base64 的问题
java 后台使用的是org.apache.commons.codec.binary.Base64 app 使用的是android.util.Base64;
两种方式简单的demo
/**
* AES
*/
@Test
fun AESAppContext() {
val secretKey: String = AESUtils.generateKey()
val name = "admin"
val pass = "123456"
val loginVo = LoginVo(name, pass)
val dataString = GsonUtils.toJson(loginVo)
println("AES加密前:$dataString")
Log.d("xxx", "AES加密前:$dataString")
val encrypt = AESUtils.encrypt(secretKey, dataString)
println("AES加密后:$encrypt")
Log.d("xxx", "AES加密后:$encrypt")
val decode = AESUtils.decrypt(secretKey, encrypt)
println("AES解密后:$decode")
Log.d("xxx", "AES解密后:$decode")
}
/**
* Rsa
*/
@Test
fun RSAAppContext() {
val PublicKey: String = ApiSecurityUtil.publicKey
// val dataString: String = "1111111"
val name = "admin"
val pass = "123456"
val loginVo = LoginVo(name, pass)
val dataString: String = GsonUtils.toJson(loginVo)
println("RSA加密前:$dataString")
Log.d("xxx", "RSA加密前:$dataString")
// 从字符串中得到公钥
val publicKey: PublicKey = RSAUtils.loadPublicKey(PublicKey);
// 从文件中得到公钥
// val inPublic: InputStream = getResources().getAssets().open("rsa_public_key.pem")
// val publicKey: PublicKey = RSAUtils2.loadPublicKey(inPublic)
// 加密
val encryptByte: ByteArray = RSAUtils.encryptData(dataString.toByteArray(), publicKey)
// 为了方便观察吧加密后的数据用base64加密转一下,要不然看起来是乱码,所以解密是也是要用Base64先转换
// 为了方便观察吧加密后的数据用base64加密转一下,要不然看起来是乱码,所以解密是也是要用Base64先转换
val encrypt = Base64Utils.encode(encryptByte)
println("RSA加密后:$encrypt")
Log.d("xxx", "RSA加密后:$encrypt")
val privateKey: PrivateKey = RSAUtils.loadPrivateKey(ApiSecurityUtil.privateKey)
val decryptByte: ByteArray =
RSAUtils.decryptData(Base64Utils.decode(encrypt), privateKey)
val decode = String(decryptByte)
println("RSA解密后:$decode")
Log.d("xxx", "RSA解密后:$decode")
}
这样为了能明白,rsa 和 AES 里面需要什么key 和 解决的具体问题了。
后台思路
之前写好了登录界面
@PostMapping("/login")
public R login(@ModelAttribute LoginVo loginVo) {
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
queryWrapper.in("account", loginVo.getName());
SysUser one = sysUserService.getOne(queryWrapper);
if (one == null) {
return R.error("用户名不存在");
}
if (one.getPassword().equals(loginVo.getPass())) {
return R.ok();
} else {
return R.error("密码错误");
}
}
改造之后
@PostMapping("/loginAndroid")
public R loginAndroid(@ModelAttribute R r) {
Object data = r.getData();
if (data == null) {
return R.error("请输入内容");
}
String encrypt = JSONUtil.toJsonStr(r.getData());
AesVo aesVo = JSONUtil.toBean(encrypt, AesVo.class);
if (StrUtil.isEmpty(aesVo.getData()) && StrUtil.isEmpty(aesVo.getAesKey())) {
return R.error("请求产生错误");
}
String decrypt = SecurityUtil.decrypt(aesVo.getData(), aesVo.getAesKey());
if (StrUtil.isEmpty(decrypt)) {
return R.error();
}
LoginVo loginVo = JSONUtil.toBean(decrypt, LoginVo.class);
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
queryWrapper.in("account", loginVo.getName());
SysUser one = sysUserService.getOne(queryWrapper);
if (one == null) {
return R.error("用户名不存在");
}
if (one.getPassword().equals(loginVo.getPass())) {
R r1 = SecurityUtil.encrypt(one, SecurityUtil.publicKey);
return r1;
// return R.ok(one);
} else {
return R.error("密码错误");
}
}
这样不能每个要加加密的接口都得处理一下吧。
所以用aop 把获取的参数处理一些。。。。然后在对原来方法进行放行的思路。
下次分享啦。。。。
R.ok 对object 进行加密处理 可以写公共里面了。
参考blog
https://juejin.cn/post/6919760673052311559
https://www.cnblogs.com/huanzi-qch/p/10913636.html
网友评论