Tiempo inmediato: la belleza de los patrones de diseño en la práctica II (Parte 1): ¿Cómo hacer un análisis orientado a objetos del desarrollo de una función como la autenticación de interfaz?

El análisis orientado a objetos (OOA), el diseño orientado a objetos (OOD) y la programación orientada a objetos (OOP) son los tres vínculos principales del desarrollo orientado a objetos. En los capítulos anteriores, mi explicación de los tres es más teórica y general. El propósito es brindarle una comprensión general de lo que son OOA, OOD y OOP. Sin embargo, no basta con saber el "qué", es más importante para nosotros saber el "cómo", es decir, cómo realizar análisis, diseño y programación orientados a objetos.

En mi trabajo anterior, descubrí que muchos ingenieros, especialmente los ingenieros junior, no tenían mucha experiencia en proyectos, o los proyectos en los que participaron se basaban en el marco de desarrollo para completar el código como plantillas CRUD, lo que resultó en una falta de capacidades de análisis y diseño. Cuando obtienen un requisito de desarrollo más general, a menudo no saben por dónde empezar.

Para "¿cómo hacer análisis de requisitos, cómo dividir responsabilidades? ¿Qué clases deben definirse? ¿Qué atributos y métodos debería tener cada clase? ¿Cómo interactuar entre clases? ¿Cómo ensamblar clases en un programa ejecutable?" El problema es que no hay una idea clara, y mucho menos el uso de principios de diseño maduros, ideas o patrones de diseño para desarrollar código con alta cohesión, bajo acoplamiento, fácil expansión, fácil lectura y otras excelentes características.

Por lo tanto, planeo usar dos clases para combinar un caso de desarrollo real, comenzando desde el análisis de requisitos básicos, división de responsabilidades, definición de clases, interacción, ensamblaje y operación, y el análisis, diseño y programación orientados a objetos más básicos. La rutina se explicará claramente para que pueda sentar una base sólida para aprender posteriormente los principios y patrones de diseño.

No hay mucho que decir, ¡comencemos oficialmente el aprendizaje de hoy!

Introducción de casos y análisis de dificultades

Supongamos que participa en el desarrollo de un microservicio. Los microservicios exponen interfaces a otros sistemas a través del protocolo HTTP. Para decirlo sin rodeos, otros sistemas llaman a las interfaces de microservicios a través de URL. Un día, su líder lo encontró y dijo: "Para garantizar la seguridad de las llamadas de interfaz, esperamos diseñar e implementar una función de autenticación de llamadas de interfaz. Solo el sistema autenticado puede llamar a nuestra interfaz, y el sistema que no ha sido autenticado puede llamar a la nuestra. La interfaz será rechazada. Espero que usted sea responsable del desarrollo de esta tarea y se esfuerce por conectarse lo antes posible ".

El líder dejó estas palabras y se fue. ¿Qué debes hacer en este momento? ¿Sientes que hay una nube de barro en tu mente y no puedes empezar por un tiempo? ¿Por qué te sientes así? Personalmente, creo que hay dos razones principales.

1. Requisitos poco claros

Los requisitos dados por el líder son demasiado vagos, generales, no específicos y lo suficientemente detallados, y todavía hay una cierta distancia desde el aterrizaje hasta el diseño y la codificación. El cerebro humano no es bueno para pensar en problemas tan abstractos. Esto es lo que distingue al desarrollo de software real de la educación orientada a exámenes. Las preguntas de examen en la educación orientada a exámenes son generalmente preguntas muy específicas, por lo que podemos simplemente responderlas. En el desarrollo de software real, casi todos los requisitos no están claros.

Como dijimos antes, el principal objeto de análisis del análisis orientado a objetos son los "requisitos", por lo tanto, el análisis orientado a objetos puede considerarse aproximadamente como "análisis de requisitos". De hecho, ya sea un análisis de requisitos o un análisis orientado a objetos, lo primero que tenemos que hacer es refinar los requisitos generales para que sean claros y ejecutables. A través de la comunicación, la minería, el análisis, la hipótesis y el peinado, necesitamos averiguar cuáles son las necesidades específicas, cuáles se deben hacer ahora, cuáles se pueden hacer en el futuro y cuáles no se deben considerar.

2. Falta de ejercicio

En comparación con el desarrollo CRUD empresarial puro, la tarea de desarrollo de la autenticación es más difícil. Como función que no tiene nada que ver con un negocio específico, la autenticación se puede desarrollar como un marco independiente e integrarse en muchos sistemas comerciales. Como marco general reutilizado por muchos sistemas, tenemos requisitos más altos sobre la calidad del código del marco que el código comercial ordinario.

El desarrollo de un marco universal de este tipo requiere que los ingenieros tengan requisitos relativamente altos de capacidades de análisis, capacidades de diseño, capacidades de codificación e incluso capacidades de pensamiento lógico. Si por lo general haces desarrollo de negocios CRUD simple, definitivamente no tendrás mucho ejercicio en esta área, por lo tanto, una vez que encuentres este tipo de necesidades de desarrollo, es fácil perder la cabeza por falta de ejercicio y no saber por dónde empezar. Ideas.

Necesita análisis del caso

De hecho, el trabajo de análisis de requisitos es muy trivial y no hay demasiadas reglas fijas para encontrar. Por lo tanto, no pretendo enumerar aquellas metodologías que suenan útiles pero en realidad inútiles. En cambio, espero usar este ejemplo de autenticación. Permítanme mostrarles cómo se ve mi camino de pensamiento completo al enfrentar el análisis de la demanda. Espero que pueda experimentarlo por sí mismo y aplicar la analogía al análisis de necesidades de otros proyectos.

Aunque para el desarrollo de sistemas no comerciales como marcos, componentes y bibliotecas, debemos tener conocimiento de los componentes, conocimiento del marco y conocimiento de la abstracción. Las cosas desarrolladas deben ser lo suficientemente universales y no limitarse a un solo requisito comercial. No significa que podamos romper con escenarios de aplicación específicos y darnos palmadas en la cabeza para el análisis de la demanda. Hable más con el equipo empresarial e incluso participe en el desarrollo de varios sistemas empresariales, sólo así podremos conocer verdaderamente los puntos débiles del sistema empresarial y analizar las necesidades más valiosas. Sin embargo, para el desarrollo de la función de autenticación, el mayor demandante somos nosotros mismos, por lo que también podemos empezar por satisfacer las necesidades de nuestro propio sistema y luego optimizar iterativamente.

Ahora, echemos un vistazo, para el desarrollo de esta función de autenticación, ¿cómo hacemos análisis de demanda?

De hecho, esto es similar a hacer problemas algorítmicos: primero piense en la solución más simple y luego optimice. Por lo tanto, dividí todo el proceso de análisis en cuatro rondas graduales. Cada ronda es una optimización iterativa de la ronda anterior, y finalmente se forma una lista de requisitos ejecutables y que se pueden aterrizar.

1. La primera ronda de análisis fundamental

La solución más sencilla al problema de cómo realizar la autenticación es realizar la autenticación mediante el nombre de usuario y la contraseña. Distribuimos un nombre de aplicación (o ID de aplicación, AppID) y una contraseña correspondiente (o clave secreta) a cada persona que llama a quien se le permite acceder a nuestro servicio. Cada vez que la persona que llama realiza una solicitud de interfaz, lleva su AppID y contraseña. Una vez que el microservicio recibe la solicitud de llamada de la interfaz, analizará el AppID y la contraseña, y los comparará con el AppID y la contraseña almacenados en el microservicio. Si son consistentes, la autenticación es exitosa y se permite la solicitud de llamada de interfaz; de lo contrario, se rechaza la solicitud de llamada de interfaz.

2. La segunda ronda de análisis y optimización

Sin embargo, en un método de autenticación de este tipo, la contraseña debe transmitirse en texto sin cifrar cada vez. Las contraseñas se pueden interceptar fácilmente y son inseguras. Entonces, si usamos un algoritmo de encriptación (como SHA) para encriptar la contraseña y luego pasarla al micro servidor para su verificación, ¿está bien? De hecho, esto también es inseguro, debido a que la contraseña cifrada y el AppID aún pueden ser interceptados por sistemas no autenticados (o hackers), los sistemas no autenticados pueden llevar esta contraseña cifrada y el AppID correspondiente, disfrazándose como un sistema autenticado. Ven a visitar nuestra interfaz. Este es un ataque de repetición típico .

Hacer preguntas y luego resolverlas es un método de optimización iterativo muy bueno. Para el problema de ahora, podemos resolverlo con la ayuda de la autenticación OAuth. La persona que llama empalma la URL de la interfaz de solicitud con el AppID y la contraseña, y luego la cifra para generar un token. Cuando la persona que llama realiza una solicitud de interfaz, pasa este token y AppID junto con la URL al microservidor. Después de recibir los datos, el microservidor extrae la contraseña correspondiente de la base de datos de acuerdo con el AppID y utiliza el mismo algoritmo de generación de tokens para generar otro token. Utilice este token recién generado para compararlo con el token pasado por la persona que llama. Si son coherentes, se permite la solicitud de llamada de interfaz; de lo contrario, se rechaza la solicitud de llamada de interfaz.

Este esquema es un poco más complicado. Dibujé un diagrama de muestra para ayudarte a comprender todo el proceso.

Inserte la descripción de la imagen aquí

3. La tercera ronda de análisis y optimización

Sin embargo, dicho diseño todavía tiene el riesgo de ataques de repetición y todavía no es lo suficientemente seguro. El token generado al empalmar AppID y contraseña en cada URL es fijo. Después de que el sistema no autenticado intercepta la URL, el token y el AppID, aún puede pretender ser un sistema de autenticación mediante ataques de reproducción y llamar a la interfaz correspondiente a esta URL.

Para resolver este problema, podemos optimizar aún más el algoritmo de generación de tokens e introducir una variable aleatoria para que el token generado por cada solicitud de interfaz sea diferente. Podemos elegir la marca de tiempo como variable aleatoria. El token original se generó encriptando la URL, AppID y contraseña. Ahora encriptamos la URL, AppID, contraseña y marca de tiempo para generar el token. Cuando la persona que llama realiza una solicitud de interfaz, pasa el token, AppID y la marca de tiempo junto con la URL al microservidor.

Después de recibir estos datos, el microservidor verificará si la marca de tiempo actual y la marca de tiempo pasada están dentro de una determinada ventana de tiempo (por ejemplo, un minuto). Si excede un minuto, se determina que el token vence y se rechaza la solicitud de interfaz. Si no excede un minuto, significa que el token no ha expirado, y luego use el mismo algoritmo de generación de token para generar un nuevo token en el servidor, y compárelo con el token pasado por la persona que llama para ver si es consistente. Si son coherentes, se permite la solicitud de llamada de interfaz; de lo contrario, se rechaza la solicitud de llamada de interfaz.

El proceso de autenticación optimizado se muestra en la siguiente figura.

Inserte la descripción de la imagen aquí

4. Cuarta ronda de análisis y optimización

Sin embargo, podría decir que esto no es lo suficientemente seguro. ¡El sistema no autenticado aún puede llamar a nuestra interfaz interceptando la solicitud y reproduciendo la solicitud dentro de la ventana de invalidación del token de este minuto!

Tienes razón. Sin embargo, entre ataque y defensa, no hay seguridad absoluta. Lo que podemos hacer es maximizar el costo del ataque. Aunque esta solución todavía tiene lagunas, es bastante simple de implementar y no afecta excesivamente el rendimiento de la propia interfaz (como el tiempo de respuesta). Por lo tanto, considerando la seguridad, el costo de desarrollo y el impacto en el rendimiento del sistema, esta solución es un compromiso y razonable.

De hecho, hay un detalle más que no consideramos, es decir, cómo almacenar el AppID y la contraseña de cada llamador autorizado en el micro servidor. Por supuesto, este problema no es difícil. La solución más fácil de pensar es almacenarlo en una base de datos, como MySQL. Sin embargo, para desarrollar funciones no comerciales como la autenticación, es mejor no acoplarse excesivamente con sistemas específicos de terceros.

Para el almacenamiento de AppID y contraseña, es mejor que podamos admitir de manera flexible varios métodos de almacenamiento, como ZooKeeper, archivos de configuración local, centro de configuración de desarrollo propio, MySQL, Redis, etc. No necesariamente implementamos código para cada método de almacenamiento, pero al menos debe haber puntos de extensión para garantizar que el sistema tenga la flexibilidad y escalabilidad suficientes para minimizar los cambios de código cuando cambiamos de método de almacenamiento.

5. Finalizar los requisitos

En este punto, los requisitos han sido suficientemente detallados y específicos. Ahora, volveremos a describir los requisitos de acuerdo con el proceso de autenticación. Si está familiarizado con UML, también puede usar diagramas de secuencia y diagramas de flujo para describir. Sin embargo, la descripción no es el punto clave, una descripción clara es lo más importante. Teniendo en cuenta que en la siguiente parte del diseño orientado a objetos, diseñaré clases, atributos, métodos, interacciones, etc. en función de la versión de texto de la descripción del requisito, por lo que la descripción final del requisito que doy aquí es la versión en texto.

● Cuando la persona que llama realiza una solicitud de interfaz, la URL, el AppID, la contraseña y la marca de tiempo se unen, el token se genera a través de un algoritmo de cifrado y el token, AppID y la marca de tiempo se empalman en la URL y se envían al microservidor.

● Después de recibir la solicitud de interfaz de la persona que llama, el microservidor desensambla el token, AppID y la marca de tiempo de la solicitud.

● El micro servidor primero verifica si la marca de tiempo aprobada y la hora actual están dentro de la ventana de tiempo de vencimiento del token. Si ha transcurrido el tiempo de caducidad, la autenticación de la llamada de interfaz se considera un error y la solicitud de llamada de interfaz se rechaza.

● Si la verificación del token no ha expirado, el microservidor sacará la contraseña correspondiente al AppID de su propio almacenamiento, generará otro token a través del mismo algoritmo de generación de token y lo hará coincidir con el token pasado por la persona que llama. Si la autenticación es exitosa, se permite la llamada de interfaz; de lo contrario, se rechaza la llamada de interfaz.

Este es el proceso de pensamiento completo de nuestro análisis de necesidades, comenzando con las necesidades más difíciles y vagas y optimizando gradualmente a través del enfoque de "resolución de problemas", y finalmente una descripción de la demanda lo suficientemente clara y alcanzable.

Supongo que te gusta

Origin blog.csdn.net/zhujiangtaotaise/article/details/110374552
Recomendado
Clasificación