SpringCloud微服务安全实战API安全 3-5 认证
Posted 鮀城小帅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud微服务安全实战API安全 3-5 认证相关的知识,希望对你有一定的参考价值。
1. 常见问题
日常开发中会遇到的问题:
- 各种校验: 非空、唯一性等,用于保证数据的完整性
- 密码加密:对密码进行加密存储,保证安全性
- Https访问:保证数据传输的安全性
2. 各种校验
2.1 validation 校验
使用 javax.validation 提供的各种规则对参数进行校验
2.2 接口层面的校验
(1)在接口相关的参数上添加校验注解,如:@NotBlank(message="……")
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
(2)接口形参添加 @Validated 注解开启校验
@PostMapping
public UserInfo create(@RequestBody @Validated UserInfo user){
return userService.create(user);
}
(3)重启程序访问接口
测试数据:将username值赋为空串“”,这不符合要求,会被校验到
请求的返回值结果:
Response返回400状态码说明:客户端请求服务端发生错误,这符合我们的测试预期。
开发工具控制台打印校验结果:
从打印的信息可知,当前返回400是因为校验到 username 是空的,所以服务器后续流程没有继续下去。
2.3 数据库层面的校验
@Column(unique = true)
@NotBlank(message = "用户名不能为 null")
private String username;
这是User.java类的参数,对数据库层面进行加密,也就是对插入到数据库的字段进行校验操作。这里虽然有添加了 @NotBlank(message="……") 注解做校验,但这个注解其实是逻辑层面的。它只会校验在代码层面是否为空。
在数据层面要使用 @Column(unique=true)、@Column 这样的注解做校验,前者加 unique 用于校验是否在数据库表中列是唯一的参数,@Column 用于校验插入DB的参数是否为空。
2.4 优化处理validated校验后的返回结果
当前返回给客户端的结果并没有有效的信息,不利于客户端做处理,而且也不适合直接将400状态码抛给用户。
(1)创建 ValidParamExceptionHandler.java 处理类
package com.imooc.security.filter;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName ValidParamExceptionHandler
* @Description TODO
* @Author wushaopei
* @Date 2021/5/1 16:44
* @Version 1.0
*/
@ControllerAdvice
public class ValidParamExceptionHandler {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Map<String, Object> allExceptionHandler(Exception e){
Map<String, Object> map = new HashMap<>(2);
if(e instanceof BindException) {
BindException ex = (BindException)e;
BindingResult bindingResult = ex.getBindingResult();
StringBuilder errMsg = new StringBuilder(bindingResult.getFieldErrors().size() * 16);
errMsg.append("Invalid request:");
for (int i = 0 ; i < bindingResult.getFieldErrors().size() ; i++) {
if(i > 0) {
errMsg.append(",");
}
FieldError error = bindingResult.getFieldErrors().get(i);
errMsg.append(error.getField()+":"+error.getDefaultMessage());
}
map.put("errcode", 500);
map.put("errmsg", errMsg.toString());
}
else {
map.put("errcode", 500);
map.put("errmsg", e.getMessage());
}
return map;
}
}
(2)优化后的校验返回结果:
上图中,向前端返回的不再是400状态码,而是200。并且也将后台所发生的的问题代表请求处理有问题的 400状态码 以及 “用户名不能为空” 字段抛给了前端,这样有利于前端进行处理。
当然,这是一个比较粗糙的返回结果。最好还是返回一个json格式的结果,更有利于前端的处理。
3. 密码加密
通常用与业务相关的信息做加盐加密。
如:用户登录信息Token用 用户名+32位随机串+时间戳加密。
如果是简单使用用户信息,如:用户名+密码来做加密,这种方式是没有保证的。
3.1 注册用户——加密密码
// 加密
user.setPassword(SCryptUtil.scrypt(user.getPassword(),32768,8,1));
注册请求:
加密后的用户密码
3.2 Basic 重构密码校验,添加解密后校验密码
if(user != null && !SCryptUtil.check(password,user.getPassword())){
//认证通过,存放用户信息
request.setAttribute("user", user);
}
4. Https 访问
- 单向认证,就是传输的数据加密过了,但是不会校验客户端的来源
- 双向认证,如果客户端浏览器没有导入客户端证书,是访问不了web系统的,找不到地址
大部分情况下,我们的项目都是双向认证的,使用Https能更安全的保证系统的安全性。
以上是关于SpringCloud微服务安全实战API安全 3-5 认证的主要内容,如果未能解决你的问题,请参考以下文章
Spring Cloud微服务安全实战_3-2_第一个API及注入攻击防护