一、基于token的身份认证
- 1、客户端(Web浏览器、APP、小程序等)调用登录服务
- 2、登录服务通过验证后生成token,返回token给客户端同时保持token到服务端
- 3、客户端在后续请求中携带token请求服务端
- 4、服务端拿请求中的token来与服务端存储的token比较来判断该客户端是否已经认证
基于token的身份认证.png
二、基于Cookie和session的身份认证
- 1、Web浏览器调用登录请求
- 2、登录服务通过验证后生成一个有时效性的sessionId,同时在内存中创建一个session空间来存放sessionId的相关信息。返回一个Set-Cookie的header将sessionId存入浏览器
- 3、客户端在后续请求中把sessionid作为请求头中的Cookie信息携带上
- 4、服务端根据sessionid在内存中查找到相应的session来获取会话相关信息
基于Cookie和session的实现.png
三、Web浏览器请求
@Slf4j
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private IRavenUserService userService;
@GetMapping("/login")
public void login(@Validated RavenUserInfo userInfo, HttpServletRequest request) {
RavenUserInfo user = this.userService.login(userInfo);
log.info(user.toString());
// 存储到session
request.getSession().setAttribute("user", user);
}
}
raven:
user:
allowList: #需要放行的请求
- /users/login # 登录请求
/**
* 请求认证过滤器
*/
@Slf4j
@Order(2)
@Component
public class AuthenticationFilter extends OncePerRequestFilter {
@Autowired
private IRavenUserService userService;
@Autowired
private RavenAllowsUrlConfig allowsUrlConfig;
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
logger.info("2-认证过滤器");
// 直接放行
if (this.allowsUrlConfig.getAllowList().contains(request.getRequestURI())) {
filterChain.doFilter(request, response);
return;
}
String header = request.getHeader("Authorization");
if (StringUtils.isNotBlank(header)) {
String token64 = StringUtils.substringAfter(header, "Basic ");
String token = new String(Base64Utils.decodeFromString(token64));
String[] items = StringUtils.splitByWholeSeparatorPreserveAllTokens(token, ":");
if (items.length != 2) {
log.info("用户身份认证错误!!!");
throw new RuntimeException("用户身份认证错误!!!");
}
String username = items[0];
String password = items[1];
RavenUserInfo userInfo = this.userService.getByName(username);
if (userInfo != null && userInfo.getPassword().equals(password)) {
request.getSession().setAttribute("user", userInfo);
}
}
filterChain.doFilter(request, response);
}
}
/**
* ACL权限拦截器
*/
@Component
public class RavenAclInterceptor extends HandlerInterceptorAdapter {
@Autowired
private RavenAllowsUrlConfig allowsUrlConfig;
/**
* 请求前缀拦截处理
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
boolean result = true;
if (this.allowsUrlConfig.getAllowList().contains(request.getRequestURI())) {
return result;
}
// 获取用户信息
RavenUserInfo userInfo = (RavenUserInfo) request.getSession().getAttribute("user");
if (null == userInfo) {
// 用户未认证
response.setContentType("text/plain");
response.getWriter().write("need authentication");
response.setStatus(HttpStatus.UNAUTHORIZED.value());
result = false;
}
else {
// 用户没有权限
String method = request.getMethod();
if (!userInfo.hasPermission(method)) {
response.setContentType("text/plain");
response.getWriter().write("forbidden");
response.setStatus(HttpStatus.FORBIDDEN.value());
result = false;
}
}
return result;
}
}
- 为了防止session攻击,确保每次登录都生成新的session
@GetMapping("/login")
public void login(@Validated RavenUserInfo userInfo, HttpServletRequest request) {
RavenUserInfo user = this.userService.login(userInfo);
log.info(user.toString());
HttpSession session = request.getSession(false);
if (session != null) {
// 把已存在的session过期
session.invalidate();
}
// 保证每一次登录都是一个新的session
request.getSession(true).setAttribute("user", user);
}
网友评论