Есть исследования, связанные с Java-блокчейном.
В рамках монолитной архитектуры приложения обычно используется модель контроля доступа на основе ролей и прав пользователей (например, Shiro). В этом случае для каждого интерфейса метода применяются аннотации RequireRole и RequirePermission. При вызове метода выполняется сопоставление с конфигурацией базы данных или кэша.
При микросервисной архитектуре шлюз используется в качестве точки входа для всех сервисов. Шлюз выполняет функции аутентификации, распределения и ограничения трафика.
Ранее каждый отдельный сервис выполнял собственную аутентификацию. Теперь все эти функции переданы шлюзу Zuul. Это позволяет централизовать управление доступом и избежать несанкционированных запросов, которые могут привести к перегрузке шлюза.
Для реализации этой модели существует множество подходов. Однако у неё есть два основных недостатка:
Более предпочтительным вариантом является использование подхода, аналогичного Shiro, когда аннотации Role и Permission добавляются непосредственно к контроллерам или методам интерфейсов. В этом случае только важные интерфейсы будут связаны с правами доступа, что упрощает управление.
После того как каждый микросервис определит свои права доступа, шлюз будет выполнять аутентификацию при каждом запросе. Микросервисам больше не нужно самостоятельно управлять доступом.
Как реализовать эту модель?
Каждый микросервис после запуска загружает свои права доступа в Redis. Шлюз отслеживает изменения в Redis и обновляет информацию о правах доступа в памяти. Сервис Auth отвечает за управление пользователями, ролями и меню. Он также обновляет данные в Redis, а шлюз следит за изменениями.
Когда поступает запрос, шлюз проверяет соответствие адреса интерфейса, метода запроса и ролей пользователя с информацией, хранящейся в его памяти. На основании этого принимается решение о разрешении или блокировке запроса.
Эта структура была реализована в виде фреймворка, который можно использовать, добавив зависимость в файл pom.xml. Также доступен пример использования в каталоге examples.
Использование фреймворка просто: достаточно добавить зависимость и настроить соединение с Redis. После запуска приложения права доступа автоматически загружаются в Redis.
Этот сервер отвечает за управление данными пользователей, ролей и меню, а также за их загрузку в Redis. Для этого используются классы AuthCache и AuthInfoHolder.
На стороне шлюза необходимо выполнить следующие шаги:
Проверка прав доступа включает несколько шагов:
Метод check принимает несколько параметров: имя микросервиса, метод запроса (GET, POST, PUT, DELETE), адрес запроса, роль пользователя и набор его прав. Все эти параметры можно получить из запроса HttpServletRequest.
Шлюз сравнивает информацию о запросе с данными, полученными от микросервисов и сервера аутентификации. Результат проверки возвращается пользователю.
Если роль или набор прав пользователя пусты, рекомендуется запросить информацию с сервера аутентификации для обновления данных.
Фреймворк поддерживает функцию чёрных и белых списков IP-адресов. Чтобы включить эту функцию, необходимо добавить аннотацию @EnableWhiteList или @EnableBlackList. Затем следует реализовать интерфейс IpRuleChecker. ``` public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest serverHttpRequest = ctx.getRequest();
String jwtToken = serverHttpRequest.getHeader(AUTHORIZATION);
if (jwtToken == null) {
//没有Authorization
throw new NoLoginException();
}
Claims claims = jwtUtils.getClaimByToken(jwtToken);
if (claims == null) {
throw new NoLoginException();
}
logger.info("token的过期时间是:" + (claims.getExpiration()));
if (jwtUtils.isTokenExpired(claims.getExpiration())) {
throw new NoLoginException();
}
//获取userId和userRole
String userId = claims.get(USER_ID) + "";
String userType = (String) claims.get(USER_TYPE);
//取到该用户的 role、permission
//从自己内存读取,可能为空,说明redis里没有,就需要从 auth 服务读取
Set<String> userRoles = authInfoHolder.findByUser(userId);
if (CollectionUtils.isEmpty(userRoles)) {
String roles = authFeignClient.findRolesByUser(Long.valueOf(userId));
userRoles = FastJsonUtils.toBean(roles, Set.class);
}
Set<String> roleCodes = authInfoHolder.findByRole(userRoles.iterator().next());
if (CollectionUtils.isEmpty(roleCodes)) {
String codes = authFeignClient.findCodesByRole(Long.valueOf(userRoles.iterator().next()));
roleCodes = FastJsonUtils.toBean(codes, Set.class);
}
//访问 auth 服务的 GET /project/my 接口
int code = authChecker.check(
serverHttpRequest,
userType, //这里正常应该是userRoles。但是我的业务是根据USER_TYPE在代码里作为RequireRole的。按自己的实际填写
roleCodes);
switch (code) {
case CODE_NO_APP:
throw new NoLoginException(code, "不存在的服务");
case CODE_404:
throw new NoLoginException(code, "无此接口或GET POST方法不对");
case CODE_NO_ROLE:
throw new NoLoginException(code, "用户无该接口所需 role");
case CODE_NO_CODE:
throw new NoLoginException(code, "用户无该接口所需权限");
case CODE_OK:
ctx.addZuulRequestHeader(USER_ID, userId);
ctx.addZuulRequestHeader(USER_TYPE, userType);
default:
break;
}
return null;
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )