美文网首页
API 安全机制 | 认证

API 安全机制 | 认证

作者: 乌鲁木齐001号程序员 | 来源:发表于2020-07-12 11:25 被阅读0次

认证 vs 登录

  • 认证和登录不一样,登录是获取用户信息,认证是验证用户身份是否合法;
  • 登录的行为,在一段时间内,往往只发生一次;认证的行为,是每次请求调用业务逻辑的时候,都会做的;
  • 认证不管成没成功,都会往下走,进入审计步骤去记录;最终请求能不能通过,是需要授权机制去决定的,比如认证机制没生效,不知道当前用户是谁,但是这个请求任然可能是可以调用业务逻辑的,比如商品查询;登录如果没成功,就不会往下走了;

基于 HTTP 的认证 | HTTP Basic 认证

步骤
  • 准备认证信息:用户名、密码;
  • 对认证信息做 Base64 加密;
  • 把加密后的内容填入 HTTP 的 Authorization 头,以 Basic 开头;
  • 认证没有通过的话,要返回 401;
代码实现
package com.lixinlei.security.api.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.lixinlei.security.api.dao.UserRepository;
import com.lixinlei.security.api.entity.User;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;
import org.springframework.web.filter.OncePerRequestFilter;

import com.lambdaworks.crypto.SCryptUtil;

@Component
@Order(2)
public class BasicAuthecationFilter extends OncePerRequestFilter {

    @Autowired
    private UserRepository userRepository;

    /**
     * Authorization 中携带的认证信息,是 username:password 经过 Base64 加密之后的值;
     * 该 Filter 验证的是,username:password 中的信息是否指向同一个用户;
     * @param request
     * @param response
     * @param filterChain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        System.out.println(2);

        // 这里从 Authorization 中取出的,就直接是带了 Basic 开头的,经过 Base64 加密了的字符串
        String authHeader = request.getHeader("Authorization");
            if(StringUtils.isNotBlank(authHeader)) {

            String token64 = StringUtils.substringAfter(authHeader, "Basic ");
            String token = new String(Base64Utils.decodeFromString(token64));
            String[] items = StringUtils.splitByWholeSeparatorPreserveAllTokens(token, ":");

            String username = items[0];
            String password = items[1];

            User user = userRepository.findByUsername(username);

            if(user != null && SCryptUtil.check(password, user.getPassword())) {
                request.getSession().setAttribute("user", user.buildInfo());
                request.getSession().setAttribute("temp", "yes");
            }
        }

        // 即使认证没通过,请求也要放行到下一个安全机制:审计
        try {
            filterChain.doFilter(request, response);
        } finally {
            HttpSession session = request.getSession();
            if(session.getAttribute("temp") != null) {
                session.invalidate();
            }
        }
    }

}
业务接口
/**
 * 想要获取的用户信息,必须和 Authorization 中的用户信息一致;
 * @param id 用这次请求想要获取的用户的 Id;
 * @param request request.Session 中存放的用户信息,是请求头 Authorization 中携带的,在之前的 Filter 中解析出来存放进 Session 的;
 * @return
 * @throws IOException
 */
@GetMapping("/{id}")
public UserInfo get(@PathVariable Long id, HttpServletRequest request) throws IOException {
    UserInfo user = (UserInfo) request.getSession().getAttribute("user");

    if(user == null || !user.getId().equals(id)) {
        throw new RuntimeException("身份认证信息异常,获取用户信息失败");
    }

    return userService.get(id);
}

相关文章

网友评论

      本文标题:API 安全机制 | 认证

      本文链接:https://www.haomeiwen.com/subject/cylgcktx.html