Микросервис системы фактического разрешения полевого драйвера

Микросервисы
Микросервис системы фактического разрешения полевого драйвера

Быть службой разрешений в системе арендатора для проверки подлинности и авторизации пользователей. Мы назовем службу какoneday-auth-server

написать впереди

DDD (Domain Driven Design) включает в себя несколько концепций, сущностей, объектов значений, агрегаций и ограниченных контекстов. Эта статья включает в себя только практику, и объяснение концепции будет помещено в следующую статью, в то время как предыдущаяЗачем нам нужен доменно-ориентированный дизайнКак научно-популярный пост, можно оглянуться и понять после прочтения кода.Заодно можно сравнить существующие проекты.Если знаешь, то надо знать почему.С какими проблемами часто сталкиваешься и почему DDD может лучше решить проблему ответственности программного обеспечения.

Описание требования

  1. Эта функция аутентификации при входе в систему, параметры реестра успешно зарегистрированы, ошибки входа обрабатываются, такие как блокировка IP, сбой блокировки номера, чем другие способы

  2. ​ Функция авторизации заключается в предоставлении ролей и разрешений аутентифицированным пользователям, а также включении защиты ресурса. Пользователи, не имеющие разрешения на доступ к ресурсу, не смогут получить к нему доступ.

    Эта статья подробно расскажет, как реализовать первую функцию под руководством DDD.

Домены, поддомены и ограниченные контексты

Первое, что мы понимаем, это то, чтополеУ этого слова слишком много значений, оно может обозначать не только всю бизнес-систему, но и определенный основной домен или вспомогательный поддомен. Чтобы привести неуместный пример, предположим, что мы изначально хотели реализовать эту функцию в модуле с именем account, а также функцию информации о пользователе.Учетная запись - это большое поле, большой пирогoneday-authЭто некий кусок этого большого пирога, а информация о пользователе — еще один кусок пирога.Авторитетный поддомени поддомен информации о пользователе. Поддомены могут быть дополнительно разделены на поддомены, нет наименьшего поддомена, есть только наиболее подходящий поддомен.

Вы почувствуете, что разделение этого микросервиса очень похоже Да, разделение микросервисов соответствует идее DDD, но если вы хорошенько об этом подумаете,Вы выучили только одну форму?Вы можете сравнить две картинки ниже, чтобы увидеть, совпадают ли они с вашими мыслями.

DDD中的划分

普通微服务的划分

​ В этой статье я разделил поддомены полномочий наКонтекст аутентификации и контекст авторизации. Для ограниченных контекстов мы сосредоточимся на границах, взятых из реализации предметно-ориентированного проектирования:

Например, термин «клиент» может иметь несколько значений. При просмотре каталога товаров «клиент» означает одно, при размещении заказа «клиент» означает другое. И вот почему: при просмотре каталога продуктов «клиенты» размещаются в контексте предыдущих покупок, лояльности, доступных продуктов, скидок и логистики. При размещении заказа контекст «клиента» включает имя, адрес доставки продукта, общую стоимость заказа и некоторые условия оплаты.

яoneday-authразработал класс вLoginUserE, используемый для представления класса сущностей пользователя для входа в систему, содержащаяся информация относится только к аутентификации и авторизации, а также должен быть класс пользователя в поддомене информации о пользователе.UserInfo, но значение представителя здесь - это информация, связанная с бизнес-системой, такая как пол и никнейм. Я полагаю, что большинство читателей, должно быть, испытали слишком много функций в классе, пытаясь создать полнофункциональный класс, и окончательный результат вы можете себе представить.

Когда пользователь входит в ограниченный контекст аутентификации, он будет рассматриваться только как ожидающий аутентификации и имеет только информацию, связанную с аутентификацией.Если пользователь входит в ограниченный контекст авторизации, он будет рассматриваться только как пользователь, который успешно прошел аутентификацию и ожидает авторизации или имеет полномочия. . Контекст аутентификации и контекст авторизации, которые мы можем

Итак, в коде я разделил два модуля пакета:

> one.day.auth:
	>> authentication :认证即用户登录,身份识别等功能
	>> authorization :授权上下文:给予用户身份,角色,权限,并判断用户是否具备访问某个功能的权限等功能

​ Увидев это, подумайте, пожалуйста, над вопросом для себя. Если вы будете следовать исходному подходу, разделите ли вы два пакета? Ваш общий подход выглядит следующим образом?

> one.day.auth.service
    >> authenticationServiceImpl
    >> authorizationServiceImpl

Если вы видите здесь внезапную борьбу мышления или даже чувство просветления, то поздравляю, вы начали культивировать мышление ДДД.

Резюме: Разница в каталоге кода с самого начала определяет ваш подход к разработке. Традиционному многоуровневому слою MVC суждено быть неспособным эффективно разделить поле для достижения объектно-ориентированной разработки.

Кодекс Практика

наслоение кода

Зачем нам нужен доменно-ориентированный дизайнУпомянуты две архитектуры: четырехуровневая архитектура и шестиугольная архитектура (она же порт-адаптер). Среди них гексагональная архитектура идет дальше от четырехслойной архитектуры, что в логическом смысле Физическая многоуровневость кода не может достичь так называемой гексагональности. Мы пока откладываем все это в сторону и сосредотачиваемся только на той цели, которую хотим.

Объекты предметной области должны заботиться только о бизнес-логике, без малейших технических подробностей, то есть напрямую не зависеть ни от чего извне, а полагаться на интерфейсы.

Прикладной уровень: обработка, не связанная с бизнесом; уровень предметной области: обработка, связанная с бизнесом; инфраструктура: реализация технических деталей, таких как сохранение и кэширование. Каталог кода состоит из следующих слоев:

> one.day.auth.authentication
> > app 应用层
> > client 二方包,这里方便起见放在了同一个Maven项目中
> > domain 领域层
> > > entity 实体包,具备行为,不具备数据状态
> > > port 端口定义,外部依赖统一定义为端口
> > > service 领域服务
> > infrastructure 基础设施层
> > > adapt 适配器,实现领域层定义的端口接口
> > > converter DTO,DO,Entity互相转换的工具类
> > > dataobject 表映射包 不具备行为,具备数据状态
> > > repository 仓储
> > > tunnel 通道

Реализация функции

Давайте посмотрим, как реализована функция входа в систему.

@Component
public class AuthenticationApp {
   /**
     * 领域层,登录领域服务
     */
    @Autowired
    private LoginService loginService;
    /**
     * 登录
     *
     * @param loginCmd
     */
    public void login(LoginCmd loginCmd) {
        //调用领域层进行登录校验
        String userId = loginService.login(loginCmd);
        //session中存放userId已证明登录
        //由于领域层主要负责登录,或者校验密码,登录成功之后的登录态设定不关心,交由应用层负责
        ProjectUtil.setSession("userId", userId);
    }
    public void addLoginUser(AddLoginUserCmd addLoginUserCmd) {
        loginService.addLoginUser(addLoginUserCmd);
    }
}

Мы видим, что прикладной уровеньAuthenticationAppСначала вызовите доменную службу доменного уровня.LoginService, когда метод не генерирует исключение, это доказывает, что проверка пользователя прошла успешно, но обратите внимание, чтоLoginServiceизОсновная роль заключается в проверке, войти или нет, то есть настройка состояния входа не его забота, не его бизнес-логика. Уровень домена только гарантирует правильность пользователя и пароля, а все остальное — это периферийный уровень, уровень приложений и даже вышестоящая служба для установки состояния входа в систему после успешной проверки.

六边形架构

Давайте посмотрим на доменный уровень, как работают доменные службы.

Сначала мы вводим два класса,LoginUserRepositoryPortиLoginUserConverter. У читателей может возникнуть сомнение, как же не быть технических подробностей, как нужно сохранять данные в базу данных, что должно включать технологию персистентности, в это время появилась гексагональная архитектура. Наш лозунг: «Не добавляйте никаких технических деталей на уровень предметной области», мы определяем любые внешние зависимости как класс порта, и конкретная реализация передается адаптерам каждого уровня для реализации соответствующих функций зависимостей посредством внедрения зависимостей. Как проверить это, чтобы увидеть, может ли ваш уровень домена это сделатьСкопируйте без искажений, то есть если просто скопировать доменную директорию в другие проекты, будет ли нормально компилироваться.

LoginUserConverterВ чем смысл существования DTO, Entity и DataObject всегда конвертируются друг в друга, и эта часть кода унифицирована в класс Converter. Я считаю, что многие проекты читателей, различные преобразования очень случайны, просто будьте счастливы :)

@Service
public class LoginServiceImpl implements LoginService {
    private final LoginUserRepositoryPort loginUserRepositoryPort;
    private final LoginUserConverter loginUserConverter;
    @Autowired
    public LoginServiceImpl(LoginUserRepositoryPort loginUserRepositoryPort, LoginUserConverter loginUserConverter) {
        this.loginUserRepositoryPort = loginUserRepositoryPort;
        this.loginUserConverter = loginUserConverter;
    }
    @Override
    public String login(LoginCmd loginCmd) {
        Optional<LoginUserE> optionalLoginUserE = loginUserRepositoryPort.findByUsername(loginCmd.getUsername());
        optionalLoginUserE.orElseThrow(() -> new BaseException(GlobalEnum.NON_EXIST));
        LoginUserE loginUserE = optionalLoginUserE.get();
        loginUserE.login(loginCmd.getPassword());
        //todo 登录成功,异步通知观察者
        return loginUserE.getUserId();
    }
    @Override
    public void addLoginUser(AddLoginUserCmd addLoginUserCmd) {
        LoginUserE loginUserE = loginUserConverter.convert2Entity(addLoginUserCmd);
        loginUserE.prepareToAdd();
        loginUserRepositoryPort.add(loginUserE);
    }
}

​ Доменные службыLoginServiceImplПервое, что получается через внедрение зависимостейLoginUserRepositoryPortПерейдите к запросу, чтобы получить зарегистрированного пользователяLoginUserE, если он существует, вызовитеloginметод. ПосмотримLoginUserEЧто это?

@Data
public class LoginUserE extends Unique {
    public static final String COMMON_SALT = "commonSalt";
    /**
     * 登录用户名
     */
    private String username;
    /**
     * 登录密码
     */
    private String password;
    /**
     * 盐
     */
    private String salt;
    /**
     * 加密算法
     */
    private EncryptionAlgorithmV encryptionAlgorithmV;
    /**
     * 业务唯一ID
     */
    private String userId;
    private TenantIdV tenantIdV;
    /**
     * 比较密码
     *
     * @param sendPwd 传入的密码
     * @return true/false
     */
    public boolean login(String sendPwd) {
        //检查available
        //错误次数限制
        //锁号 ip
        return StringUtils.equals(password, encryptionAlgorithmV.getPasswordEncoder().encoder(sendPwd, salt));
    }
    /**
     * 密码加密
     */
    public void encryptPassword() {
        this.setSalt(RandomStringUtils.randomNumeric(8));
        this.setPassword(encryptionAlgorithmV.getPasswordEncoder().encoder(password, salt));
    }
}

Логика кода на самом деле очень проста, есть несколько расширенных функций, которые не были реализованы: одна для работы в различных сценариях неудачного входа в систему, а вторая для реализации разных шифраторов для пользовательских систем под разными тенантами. Функция переносится из класса богослужений в класс сущностей с реальным значением, которые имеют реальное поведение и соответствуют единому стандарту ответственности класса.

​ Даже если объяснение функции входа в систему здесь закончилось, есть одна функция, которую я не разработал, а именноВход в систему выполнен успешно, и наблюдатель получает уведомление асинхронно., DDD выступает как за разработку, управляемую событиями, так и за согласованность в конечном счете. Это на самом делеПринцип единой ответственности для классовСвязанный.在整个登录功能中,чекявляется первым шагом, проверка прошла успешно, за которой следуетРазрешить, это отношения восходящего и нисходящего потоков, и основная бизнес-логика не должна быть написана вместе.В традиционных проектах MVC они абсолютно связаны. Использование управляемого событиями может разделить их, будь то асинхронный или синхронный, для простоты вы можете напрямую использовать EventBus guava.

Дизайн и характеристики слоя сохраняемости не рассматриваются в этой статье и не могут быть выполнены за один шаг.На самом деле, если вы все еще заботитесь об этом, это доказывает, что вы еще не поняли DDD. Основное внимание уделяется бизнес-логике, никаких технических деталей. Постоянство — это всего лишь технология хранения.

Суммировать

Бизнес-уровень выполняет небизнес-логику, доменный уровень выполняет только бизнес-логику и использует режим адаптера порта для изоляции внешних зависимостей.Стандарт тестирования заключается в том, что копия не имеет псевдонима. Первый шаг ограниченного контекстного разделения является критическим. Разделение в начале определяет, являетесь ли вы объектно-ориентированным или процессно-ориентированным. Не позволяйте технологии настойчивости поддаваться нашим идеям развития. Наш лозунг "Слой домена не приправлен какими-либо техническими деталями", наша цельнастоящая объектно-ориентированная разработка, наш идеалникогда не работай сверхурочно! ! ! '

​ Не делайте ошибок проходя мимо, ваши лайки лучшая мотивация поддержать меня

Адрес источника:GitHub.com/IA mway fee/one…

Автор:Пожалуйста, назовите меня красным шарфом   

Источник:nuggets.capable/post/684490…

  Перепечатка этого блога приветствуется, но данное заявление должно быть сохранено без согласия автора, а ссылка на исходный текст дана в явном месте на странице статьи, в противном случае сохраняется право привлечения к юридической ответственности.