javaweb基础登陆到security
1.一个简单的HTML例子看看用户信息安全
初学者常用操作就是写一个form然后将请求后端的接口,代码如下。
<form action = "sign-in" method = "POST">
用户名:<input id="username" name="username" type="text" />
密码:<input id="password" name="password" type="password" />
<button type="submit">登陆</button>
</form>
form表单会在提交请求时,会获取form中input标签中存在name的属性,作为HTTP请求的body中的参数传递给后台,进行登录校验。
这种方式会会暴露我传输的密码,假设我们的账号信息如下:
账号 | 密码 |
---|---|
jack | 123456 |
当点击登陆后,按F12即可看到你请求的内容,就可以看出密码是明文的。
2.改进添加密文
于是我们就想到了给密码加密后在通过http请求传输,常见的加密算法有:对称加密和非对称加密
2.1.对称加密算法
A与 B 之间之间的通讯数据都用同一套的密钥来进行加密解密。
2.2.非对称加密算法
用公钥和私钥来加解密的算法。打个比方,A 的公钥加密过的东西只能通过 A 的私钥来解密;同理,A 的私钥加密过的东西只能通过 A 的公钥来解密。顾名思义,公钥是公开的,别人可以获取的到;私钥是私有的,只能自己拥有。
详情可以查看文章:
2.3使用对称加密算法
加密解密在前后台协商后,似乎是个不错的办法,比如,前台使用一个字符串位移+字符串反转的简单方法
例如:qweasd123 -> 123qweasd
然后传给服务器,服务器就将前面3位移动到最后面:123qweasd -> qweasd123
这个方法虽然可以实现加密,但是前后端加密解密需要同时修改代码,所以不采用这种方法.
2.4采用非对称加密算法
利用不可逆加密散列函数MD5(string),用户在注册输入密码的时候,就存储MD5(password)值,并且在WEB端先进行MD5(password),然后将密码传输至后台,与数据库中的密文进行比较。
代码入下
<form action = "http://localhost:8080/sign-in" method = "POST">
用户名:<input id="username" name="username" type="text" />
密码:<input id="password" name="password" type="password" />
<input type="submit" onclick="md5_encryption()" />
</form>
<!--这里需要直接引入md5.js 和 jquery.js-->
<script type="text/javascript">
function md5_encryption(){
document.getElementById('password').value = hex_md5(
document.getElementById('password').value
)
}
</script>
再来看看我们的请求的内容
2.5后端对前端传输的信息进行验证
思路:后端将正确的密码通过MD5生成字符串,然后和前端通过MD5加密的信息进行比对,如果不一样就说明,密码错误,代码如下。
1.MD5Utils
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Utils {
public static String getMd5(String str) {
try{
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str.getBytes());
byte hash[] = md.digest();
StringBuffer sb = new StringBuffer();
int i = 0;
for (int offset = 0; offset < hash.length; offset++) {
i = hash[offset];
if (i < 0) {
i += 256;
}
if (i < 16) {
sb.append("0");
}
sb.append(Integer.toHexString(i));
}
return sb.toString();
}catch (NoSuchAlgorithmException e){
e.printStackTrace();
}
return null;
}
}
Controller
@RestController
public class LoginCtroller {
@PostMapping("/sign-in")
public String login(LoginParam loginParam){
User user = new User("Jack","123456"); //模拟用户,你也可以改成通过数据库查询
if(loginParam == null){ //判断参数是否为空
throw new NullPointerException();
}
String protoMd5 = MD5Utils.getMd5(user.getPassword());
if(user.getUsername().equals(loginParam.getUsername())&& protoMd5.equals(loginParam.getPassword())){
return "欢迎"+loginParam.getUsername();
}else{
return "账号或密码错误";
}
}
}
实体类User
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class User {
private String username;
private String password;
}
登陆参数类LoginParam
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginParam {
private String username;
private String password;
/**
* 记住我
*/
private String remenberMe;
}
另外还还有情况就是前后端的MD5加密结果不一致,请读者自行百度。
3.token令牌
前后端分离场景。现在非常流行的前后端分离的开发模式大大提高了项目的开发效率。职责、分工明确。
但是由于HTTP是无状态的(就是这一次请求并不知道上一次请求的内容),当用户登录时,根据用户的username作为key,生成随机令牌(例如UUID)作为value缓存在Redis中,并且将token返回给客户端,当客户端登录时,将完成校验,并且删除Redis中的那条缓存记录。
那么每次从服务器中获取认证的token,确实能保证HTTP请求是由前端传回来的了,因为token在每次登陆后都会删除并被重置,会导致黑客尝试重放账号密码数据信息来登陆的时候导致无法成功登陆。
总而言之,就是我拿到了账号以及密码的密文也登陆不了,因为,如果请求不包含后台认证的令牌token,是个非法请求。
持续更新中。。。。
4.Security登陆
blalala...
5.Security实现短信/OAuth登陆
blalala...
6.Security核心源码分析
blala...
参考文章:https://www.javazhiyin.com/36974.html