SpringCloud微服务安全API安全 2-4 认证
Posted 鮀城小帅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud微服务安全API安全 2-4 认证相关的知识,希望对你有一定的参考价值。
1.认证
认证:登录和认证是 两个概念,比如你两周、一个月,可能只登录了一次,但认证却是每次访问都要经过的步骤。
对于图中的认证不成功,也要继续处理,这个我觉得得看业务,比如管理系统,不登录就不让你访问,但对于比如电商的商品信息,不登录,也是可以访问的。
2. 编写一个用户注册服务
2.1 根据单一职责原则创建 UserInfo 用于接口返回
单一职责原则:用户注册服务,得新建一个UserInfo类,用来接收前端传过来的注册用户信息,而最好不要使用User类直接接收。
新增方法,可以将UserInfo返回,前端可以做相应的展示。
@Data
public class UserInfo {
private Long id ;
private String name;
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
}
业务层修改 UserInfo ,包括UserServiceImpl
public interface UserService {
UserInfo create(UserInfo user);
UserInfo update(UserInfo user);
void delete(Long id);
UserInfo get(Long id);
List<UserInfo> query(String name);
}
标准三层结构: UserController ----- > UserService -----> UserRepository 。
数据处理:
- UserService --------> UserRepository ,查询返回 User对象
- UserController ---------> UserService , BeanUtils.copyProperties(UserInfo,User) 处理返回 UserInfo
2.2 启动程序并添加用户
业务代码
@Override
public UserInfo create( @Valid UserInfo userInfo) {
/**
* 将密码加密成明文
*/
User user = new User();
BeanUtils.copyProperties(userInfo,user);
// 加密
user.setPassword(SCryptUtil.scrypt(user.getPassword(),32768,8,1));
userRepository.save(user);
userInfo.setId(user.getId());
return userInfo;
}
接口
@PostMapping
public UserInfo create(@RequestBody @Validated UserInfo user){
return userService.create(user);
}
测试及结果:
3. HttpBasic认证
3.1 Basic 认证标准
在HTTP协议进行通信的过程中,HTTP协议定义了基本认证过程以允许HTTP服务器对WEB浏览器进行用户身份证的方法,当一个客户端向HTTP服务器进行数据请求时,如果客户端未被认证,则HTTP服务器将通过基本认证过程对客户端的用户名及密码进行验证,以决定用户是否合法。
具体做法是,将用户名、密码用:号隔开,然后base64编码,放在请求头的Authorization字段里,值是Basic base64编码的字符串。
- RequestHeader
- Authorization:Basic Base64(用户名:密码)
比较简单,但是安全性不高。
3.2 创建HttpBasic过滤器实现认证机制
(1)编写HttpBasic过滤器
package com.imooc.security.filter;
import com.imooc.security.user.User;
import com.imooc.security.user.UserRepository;
import com.lambdaworks.crypto.SCryptUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @ClassName BasicAuthecationFilter
* @Description TODO
* @Author wushaopei
* @Date 2020/10/17 14:20
* @Version 1.0
*/
@Component
public class BasicAuthecationFilter extends OncePerRequestFilter{
@Autowired
private UserRepository userRepository;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 获取请求头中的认证信息
String authHeader = request.getHeader("Authorization");
// 判断认证信息是否存在,有就进行验证
if(StringUtils.isNotBlank(authHeader)){
// 截取认证信息中的basic信息
String token64 = StringUtils.substringAfter(authHeader,"Basic ");
String[] items = StringUtils.splitByWholeSeparatorPreserveAllTokens(token,":");
String token = new String(Base64Utils.decodeFromString(token64));
String username = items[0];
String password = items[1];
User user = userRepository.findByUsername(username);
// 当前用户不为空与密码正确的情况下,认证通过,并将相关用户数据存入到请求域中
if(user != null && StringUtils.equals(password , user.getPassword())){
//认证通过,存放用户信息
request.setAttribute("user", user);
}
}
//不管认证是否正确,继续往下走,是否可以访问,交给授权处理
filterChain.doFilter(request, response);
}
}
-
处理httpbasic认证过滤器 httpbasic:请求头,即Authorization:Basic 加密字符串 加密字符串为Base64编码的用户名:密码字符串 Authorization Basic bGh5OmxoeWFwcA== 在SpringBoot里,任何实现了Filter接口的类,SpringBoot会自动把它加到web应用的过滤器链里,只要声名为Component就行了
(2)UserService.java 查询业务
@Override
public UserInfo get(Long id) {
return userRepository.findById(id).get().buildInfo();
}
(3)接口
/**
* @Description TODO 查一个用户
* @param id
* @param request
* @param response
* @return
*/
@GetMapping("/{id}")
public UserInfo get(@PathVariable Long id , HttpServletRequest request, HttpServletResponse response){
User user = (User)request.getAttribute("user");
if( user == null || !user.getId().equals(id)){
throw new RuntimeException("身份认证信息异常,获取用户信息失败");
}
return userService.get(id);
}
3.3 测试认证功能
(1)未携带Basic认证的Token
插件GET请求结果为500
开发工具校验user为null,打印抛出的异常:
(2)添加Basic认证
根据以上流程添加 Basci 认证Token到请求头中。
再次请求,本次携带有Basic认证Token
3.4 是否每个请求都带上用户名、密码
在上小节中,已经验证了携带Basic的Token可以实现认证功能,那么这里要问一个问题:难道每一个请求导到服务器时都需要带上用户名、密码吗?这样合适吗?有没有更完善的方案?
以上是关于SpringCloud微服务安全API安全 2-4 认证的主要内容,如果未能解决你的问题,请参考以下文章
SpringCloud微服务安全API安全 2-2 注入攻击防护
SpringCloud微服务安全实战API安全 3-9 总结