JavaRush /Blog Java /Random-ES /Introduzcamos el inicio de sesión regular por correo elec...

Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas.

Publicado en el grupo Random-ES
Mientras escribía mi solicitud, encontré una falta de artículos claros sobre cómo lograr que el usuario se registre tanto por correo electrónico como por redes sociales. Hubo buenos tutoriales sobre cómo configurar el formulario de inicio de sesión clásico. Hubo buenos tutoriales sobre OAuth2 . Había poca información criminal sobre cómo combinar los dos métodos. Durante el proceso de búsqueda, pudimos encontrar una solución viable. No pretende ser la verdad última, pero cumple su función. En este artículo mostraré cómo implementar un servicio de almacenamiento de notas con una configuración similar de Spring Security desde cero. Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 1Nota: es bueno que el lector haya leído al menos un par de tutoriales sobre Spring, porque la atención se centrará únicamente en Spring Security, sin explicaciones detalladas sobre repositorios, controladores, etc. De lo contrario, un artículo ya bastante extenso resultaría ser gigantesco. Contenido
  1. Creando un proyecto
  2. Creación de entidades y lógica de aplicación
    1. Entidades
    2. Repositorios
    3. Controladores
    4. paginas
  3. Configuración de Spring Security para el inicio de sesión clásico
    1. Configuración básica SecurityConfig
    2. Inicio de sesión de usuario personalizado
    3. Mejoremos el controlador.
    4. Lanzamiento
  4. Configurar OAuth2 usando Google como ejemplo en Spring Security
    1. Configuración de filtro y propiedades de aplicación.
    2. Aspectos destacados del registro de una aplicación en Google Cloud Platform
    3. Servicios personalizados de token de información de usuario
  5. Lanzamiento final del proyecto.

Creando un proyecto

Vamos a start.spring.io y formamos la base del proyecto:
  • Web: iniciar una aplicación en el Tomcat integrado, asignaciones de URL y similares;
  • JPA - conexión de base de datos;
  • Moustache es un motor de plantillas utilizado para generar páginas web;
  • Seguridad: protección de aplicaciones. Para esto se creó este artículo.
Descargue el archivo resultante y descomprímalo en la carpeta que necesite. Lo lanzamos en el IDE. Puede elegir la base de datos a su discreción. Utilizo MySQL como base de datos para el proyecto, por lo que agrego la siguiente dependencia al archivo pom.xml en el bloque <dependencias>:
<dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>5.1.34</version>
</dependency>
La configuración de application.properties actualmente es la siguiente:
spring.datasource.url=jdbc:mysql://localhost:3306/springsectut?createDatabaseIfNotExist=true&useSSL=false&autoReconnect=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=yes&characterEncoding=UTF-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=yourUsername
spring.datasource.password=yourPassword

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update

spring.jpa.properties.connection.characterEncoding=utf-8
spring.jpa.properties.connection.CharSet=utf-8
spring.jpa.properties.connection.useUnicode=true

spring.mustache.expose-request-attributes=true

Creación de entidades y lógica de aplicación

Entidades

Creemos un paquete entitiesen el que colocaremos las entidades de la base de datos. El usuario será descrito por una clase Userque implementa la interfaz UserDetails, que será necesaria para la configuración de Spring Security. El usuario tendrá una identificación, nombre de usuario (esto es correo electrónico), contraseña, nombre, función, indicador de actividad, nombre de cuenta de Google y correo electrónico ( googleNamey googleUsername).
@Entity
@Table(name = "user")
public class User implements UserDetails
{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String username;
  private String password;
  private String name;
  private boolean active;
  private String googleName;
  private String googleUsername;

  @ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
  @CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
  @Enumerated(EnumType.STRING)
  private Set<Role> roles;

    //Геттеры, сеттеры, toString(), equals(), hashcode(), имплементация UserDetails
}
Los roles de usuario se utilizan para regular el acceso en Spring Security. Nuestra aplicación solo utilizará un rol:
public enum Role implements GrantedAuthority
{
  USER;

  @Override
  public String getAuthority()
  {
     return name();
  }
}
Creemos una clase de nota con id, título de nota, cuerpo de nota e id del usuario al que pertenece:
@Entity
@Table(name = "note")
public class Note
{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String title;
  private String note;
  private Long userId;

    //Геттеры, сеттеры, toString(), equals(), hashcode()
}

Repositorios

Para guardar entidades en la base de datos, necesitamos repositorios que hagan todo el trabajo sucio por nosotros. Creemos un paquete repos, en él crearemos interfaces UserRepoheredadas NoteRepode la interfaz JpaRepository<Entity, Id>.
@Service
@Repository
public interface UserRepo extends JpaRepository<User, Long>
{}

@Service
@Repository
public interface NoteRepo extends JpaRepository<Note, Long>
{
  List<Note> findByUserId(Long userId);
}

Controladores

Nuestro servicio de notas tendrá las siguientes páginas:
  • Hogar;
  • Registro;
  • Entrada;
  • Lista de notas de usuario.
Sólo un usuario autorizado debería tener acceso a la lista de notas. Las páginas restantes son públicas. Creemos un paquete controllersque contenga una clase IndexControllerque contenga el get-mapping habitual de la página principal. La clase RegistrationControlleres responsable de registrar al usuario. La asignación posterior toma datos del formulario, guarda al usuario en la base de datos y lo redirige a la página de inicio de sesión. PasswordEncoderse describirá más adelante. Se utiliza para cifrar contraseñas.
@Controller
public class RegistrationController
{
  @Autowired
  private UserRepo userRepo;

  @Autowired
  private PasswordEncoder passwordEncoder;

  @GetMapping("/registration")
  public String registration()
  {
     return "registration";
  }

  @PostMapping("/registration")
  public String addUser(String name, String username, String password)
  {
     User user = new User();
     user.setName(name);
     user.setUsername(username);
     user.setPassword(passwordEncoder.encode(password));
     user.setActive(true);
     user.setRoles(Collections.singleton(Role.USER));

     userRepo.save(user);

     return "redirect:/login";
  }
El controlador responsable de la página de lista de notas contiene actualmente una funcionalidad simplificada, que se volverá más compleja después de la implementación de Spring Security.
@Controller
public class NoteController
{
  @Autowired
  private NoteRepo noteRepo;

  @GetMapping("/notes")
  public String notes(Model model)
  {
     List<Note> notes = noteRepo.findAll();
     model.addAttribute("notes", notes);

     return "notes";
  }

  @PostMapping("/addnote")
  public String addNote(String title, String note)
  {
     Note newNote = new Note();
     newNote.setTitle(title);
     newNote.setNote(note);

     noteRepo.save(newNote);

     return "redirect:/notes";
  }
}
No escribiremos un controlador para la página de inicio de sesión porque Spring Security lo utiliza. En su lugar, necesitaremos una configuración especial. Como de costumbre, creemos otro paquete, llamémoslo configy coloquemos la clase allí MvcConfig. Cuando escribimos la configuración de Spring Security, sabrá a qué página nos referimos cuando usamos "/login".
@Configuration
public class MvcConfig implements WebMvcConfigurer
{
  public void addViewControllers(ViewControllerRegistry registry)
  {
     registry.addViewController("/login").setViewName("login");
     registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
  }
}

paginas

Utilizo el motor de plantillas Moustache para crear páginas . Puedes implementar otro, no importa. Se ha creado un archivo meta.mustache para la metainformación que se utiliza en todas las páginas. También incluye Bootstrap para que las páginas de nuestro proyecto luzcan más bonitas. Las páginas se crean en el directorio "src/main/resources/templates". Las limas tienen la extensión bigote. Colocar el código html directamente en el artículo lo hará demasiado grande, por lo que aquí hay un enlace a la carpeta de plantillas en el repositorio de GitHub del proyecto .

Configuración de Spring Security para el inicio de sesión clásico

Spring Security nos ayuda a proteger la aplicación y sus recursos del acceso no autorizado. Crearemos una configuración de trabajo concisa en una clase SecurityConfigheredada de WebSecurityConfigurerAdapter, que colocaremos en el paquete config. Marquémoslo con la anotación @EnableWebSecurity, que habilitará la compatibilidad con Spring Security, y la anotación @Configuration, que indica que esta clase contiene alguna configuración. Nota: el pom.xml configurado automáticamente contenía la versión 2.1.4.RELEASE del componente principal Spring Boot, lo que impedía que la seguridad se implementara de la manera establecida. Para evitar conflictos en el proyecto, se recomienda cambiar la versión a 2.0.1.RELEASE.

Configuración básica SecurityConfig

Nuestra configuración podrá:
  1. Cifre las contraseñas usando BCryptPasswordEncoder:

    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Bean
    PasswordEncoder passwordEncoder()
    {
      PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
      return passwordEncoder;
    }
  2. Inicie sesión utilizando un proveedor de autenticación especialmente escrito:

    @Autowired
    private AuthProvider authProvider;
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth)
    {
      auth.authenticationProvider(authProvider);
    }
  3. Permitir el acceso de usuarios anónimos a la página de inicio, a las páginas de registro e inicio de sesión. Todas las demás solicitudes deben ser realizadas por usuarios que hayan iniciado sesión. Asignemos el “/login” descrito anteriormente como página de inicio de sesión. Si el inicio de sesión es exitoso, el usuario será llevado a una página con una lista de notas; si hay un error, el usuario permanecerá en la página de inicio de sesión. Al salir exitosamente, el usuario será llevado a la página principal.

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
      http
            .authorizeRequests()
            .antMatchers("/resources/**", "/", "/login**", "/registration").permitAll()
            .anyRequest().authenticated()
            .and().formLogin().loginPage("/login")
            .defaultSuccessUrl("/notes").failureUrl("/login?error").permitAll()
            .and().logout().logoutSuccessUrl("/").permitAll();
    }

Inicio de sesión de usuario personalizado

Uno escrito por usted mismo AuthProviderpermitirá al usuario iniciar sesión no solo por correo electrónico, sino también por nombre de usuario.
@Component
public class AuthProvider implements AuthenticationProvider
{
  @Autowired
  private UserService userService;

  @Autowired
  private PasswordEncoder passwordEncoder;

  public Authentication authenticate(Authentication authentication) throws AuthenticationException
  {
     String username = authentication.getName();
     String password = (String) authentication.getCredentials();

     User user = (User) userService.loadUserByUsername(username);

     if(user != null && (user.getUsername().equals(username) || user.getName().equals(username)))
     {
        if(!passwordEncoder.matches(password, user.getPassword()))
        {
           throw new BadCredentialsException("Wrong password");
        }

        Collection<? extends GrantedAuthority> authorities = user.getAuthorities();

        return new UsernamePasswordAuthenticationToken(user, password, authorities);
     }
     else
        throw new BadCredentialsException("Username not found");
  }

  public boolean supports(Class<?> arg)
  {
     return true;
  }
}
Como habrás notado, la clase UserServiceubicada en el paquete es la encargada de cargar al usuario services. En nuestro caso, busca un usuario no solo por el campo username, como la implementación integrada, sino también por nombre de usuario, nombre de cuenta de Google y correo electrónico de la cuenta de Google. Los dos últimos métodos nos serán útiles al implementar el inicio de sesión a través de OAuth2. Aquí la clase se da en una versión abreviada.
@Service
public class UserService implements UserDetailsService
{
  @Autowired
  private UserRepo userRepo;

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
  {
     User userFindByUsername = userRepo.findByUsername(username);
     //Остальные поиски

     if(userFindByUsername != null)
     {
        return userFindByUsername;
     }
     //Остальные проверки
     return null;
  }
}
Nota: ¡ no olvides escribir los métodos necesarios en UserRepo!

Mejoremos el controlador.

Hemos configurado Spring Security. Ahora es el momento de aprovechar esto en tu controlador de notas. Ahora cada mapeo aceptará un parámetro principal adicional, mediante el cual intentará encontrar al usuario. ¿Por qué no puedo inyectar directamente la clase User? Entonces habrá un conflicto debido a una discrepancia en los tipos de usuarios cuando escribimos un inicio de sesión a través de las redes sociales. Proporcionamos la flexibilidad necesaria por adelantado. Nuestro código de controlador de notas ahora se ve así:
@GetMapping("/notes")
public String notes(Principal principal, Model model)
{
  User user = (User) userService.loadUserByUsername(principal.getName());
  List<Note> notes = noteRepo.findByUserId(user.getId());
  model.addAttribute("notes", notes);
  model.addAttribute("user", user);

  return "notes";
}

@PostMapping("/addnote")
public String addNote(Principal principal, String title, String note)
{
  User user = (User) userService.loadUserByUsername(principal.getName());

  Note newNote = new Note();
  newNote.setTitle(title);
  newNote.setNote(note);
  newNote.setUserId(user.getId());

  noteRepo.save(newNote);

  return "redirect:/notes";
}
Nota: el proyecto tiene la protección CSRF habilitada de forma predeterminada , así que desactívela usted mismo (http.csrf().disable()) o no olvide, como autor del artículo, agregar un campo oculto con un token csrf. a todas las solicitudes de publicación.

Lanzamiento

Estamos intentando poner en marcha el proyecto.
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 1
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 2
Vemos que ha aparecido un nuevo usuario en la base de datos. La contraseña está cifrada.
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 3
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 4
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 5
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 6
Las notas se guardan en la base de datos.
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 7
Vemos que el proyecto se lanzó y se ejecuta con éxito. Para una felicidad total, solo necesitamos la posibilidad de iniciar sesión a través de las redes sociales. Bueno, ¡comencemos!

Configurar OAuth2 usando Google como ejemplo en Spring Security

Al implementar OAuth2, me basé en este tutorial oficial de Spring . Para admitir OAuth2, agregue la siguiente biblioteca a pom.xml:
<dependency>
  <groupId>org.springframework.security.oauth.boot</groupId>
  <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  <version>2.0.0.RELEASE</version>
</dependency>
Modifiquemos nuestra configuración de Spring Security en el archivo SecurityConfig. Primero, agreguemos la anotación @EnableOAuth2Client. Automáticamente mostrará lo que necesita para iniciar sesión a través de las redes sociales.

Configuración de filtro y propiedades de aplicación.

Inyectemos OAuth2ClientContext para usarlo en nuestra configuración de seguridad.
@Autowired
private OAuth2ClientContext oAuth2ClientContext;
OAuth2ClientContext se utiliza al crear un filtro que valida la solicitud de inicio de sesión social del usuario. El filtro está disponible gracias a la anotación @EnableOAuth2Client. Todo lo que tenemos que hacer es llamarlo en el orden correcto, antes del filtro principal de Spring Security. Sólo entonces podremos detectar redireccionamientos durante el proceso de inicio de sesión con OAuth2. Para hacer esto usamos FilterRegistrationBean, en el que establecemos la prioridad de nuestro filtro en -100.
@Bean
public FilterRegistrationBean oAuth2ClientFilterRegistration(OAuth2ClientContextFilter oAuth2ClientContextFilter)
{
  FilterRegistrationBean registration = new FilterRegistrationBean();
  registration.setFilter(oAuth2ClientContextFilter);
  registration.setOrder(-100);
  return registration;
}

private Filter ssoFilter()
{
  OAuth2ClientAuthenticationProcessingFilter googleFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/google");
  OAuth2RestTemplate googleTemplate = new OAuth2RestTemplate(google(), oAuth2ClientContext);
  googleFilter.setRestTemplate(googleTemplate);
  CustomUserInfoTokenServices tokenServices = new CustomUserInfoTokenServices(googleResource().getUserInfoUri(), google().getClientId());
  tokenServices.setRestTemplate(googleTemplate);
  googleFilter.setTokenServices(tokenServices);
  tokenServices.setUserRepo(userRepo);
  tokenServices.setPasswordEncoder(passwordEncoder);
  return googleFilter;
}
También necesita agregar un nuevo filtro a la función de configuración (HttpSecurity http):
http.addFilterBefore(ssoFilter(), UsernamePasswordAuthenticationFilter.class);
El filtro también necesita saber que el cliente se ha registrado a través de Google. La anotación @ConfigurationProperties especifica qué propiedades de configuración buscar en application.properties.
@Bean
@ConfigurationProperties("google.client")
public AuthorizationCodeResourceDetails google()
{
  return new AuthorizationCodeResourceDetails();
}
Para completar la autenticación, debe especificar el punto final de información del usuario de Google:
@Bean
@ConfigurationProperties("google.resource")
public ResourceServerProperties googleResource()
{
  return new ResourceServerProperties();
}
Habiendo registrado nuestra aplicación en Google Cloud Platform , agregaremos propiedades con los prefijos apropiados a application.properties:
google.client.clientId=yourClientId
google.client.clientSecret=yourClientSecret
google.client.accessTokenUri=https://www.googleapis.com/oauth2/v4/token
google.client.userAuthorizationUri=https://accounts.google.com/o/oauth2/v2/auth
google.client.clientAuthenticationScheme=form
google.client.scope=openid,email,profile
google.resource.userInfoUri=https://www.googleapis.com/oauth2/v3/userinfo
google.resource.preferTokenInfo=true

Aspectos destacados del registro de una aplicación en Google Cloud Platform

Ruta: API y servicios -> Ventana de solicitud de acceso a Credenciales OAuth:
  • Nombre de la aplicación: formulario de inicio de sesión de Spring y tutorial de OAuth2
  • Dirección de correo electrónico de soporte: su correo electrónico
  • Alcance de la API de Google: correo electrónico, perfil, openid
  • Dominios autorizados: me.org
  • Enlace a la página principal de la aplicación: http://me.org:8080
  • Enlace a la política de privacidad de la aplicación: http://me.org:8080
  • Enlace a los términos de uso de la aplicación: http://me.org:8080
Cartas credenciales:
  • Tipo: Aplicación web
  • Título: Formulario de inicio de sesión de Spring y tutorial de OAuth2
  • Fuentes de JavaScript permitidas: http://me.org, http://me.org:8080
  • URI de redireccionamiento permitidos: http://me.org:8080/login, http://me.org:8080/login/google
Nota: como Google no quiere trabajar con la dirección localhost:8080, agregue la línea “127.0.0.1 me.org” o algo similar al archivo C:\Windows\System32\drivers\etc\hosts al final. Lo principal es que el dominio tiene la forma clásica.

Servicios personalizados de token de información de usuario

¿Notaste la palabra Personalizado en la descripción de la función de filtro? Clase CustomUserInfoTokenServices. Sí, crearemos nuestra propia clase con blackjack y la posibilidad de guardar al usuario en la base de datos. Con el método abreviado de teclado Ctrl-N en IntelliJ IDEA, puede buscar y ver cómo UserInfoTokenServicesse implementa el valor predeterminado. Copiemos su código en la clase recién creada CustomUserInfoTokenServices. La mayor parte se puede dejar sin cambios. Antes de cambiar la lógica de las funciones, agreguemos UserRepoy como campos privados de la clase PasswordEncoder. Creemos setters para ellos. Agreguemos @Autowired UserRepo userRepo a la clase SecurityConfig. Observamos cómo desaparece el puntero del error en el método de creación del filtro y nos alegramos. ¿Por qué no se puede aplicar @Autowired directamente a CustomUserInfoTokenServices? Porque esta clase no recogerá la dependencia, ya que ella misma no está marcada con ninguna anotación Spring y su constructor se crea explícitamente cuando se declara el filtro. En consecuencia, el mecanismo DI de Spring no lo sabe. Si anotamos @Autowired en algo en esta clase, obtendremos una NullPointerException cuando se use. Pero a través de configuradores explícitos todo funciona muy bien. Después de implementar los componentes necesarios, el principal objeto de interés se convierte en la función loadAuthentication, en la que se recupera el Map<String, Object> con información sobre el usuario. Fue en este proyecto que implementé guardar en la base de datos un usuario que inició sesión a través de una red social. Dado que utilizamos una cuenta de Google como proveedor de OAuth2, comprobamos si el mapa contiene el campo "sub" típico de Google. Si está presente, significa que la información sobre el usuario se recibió correctamente. Creamos un nuevo usuario y lo guardamos en la base de datos.
@Override
public OAuth2Authentication loadAuthentication(String accessToken)
     throws AuthenticationException, InvalidTokenException
{
  Map<String, Object> map = getMap(this.userInfoEndpointUrl, accessToken);

  if(map.containsKey("sub"))
  {
     String googleName = (String) map.get("name");
     String googleUsername = (String) map.get("email");

     User user = userRepo.findByGoogleUsername(googleUsername);

     if(user == null)
     {
        user = new User();
        user.setActive(true);
        user.setRoles(Collections.singleton(Role.USER));
     }

     user.setName(googleName);
     user.setUsername(googleUsername);
     user.setGoogleName(googleName);
     user.setGoogleUsername(googleUsername);
     user.setPassword(passwordEncoder.encode("oauth2user"));

     userRepo.save(user);
  }

  if (map.containsKey("error"))
  {
     this.logger.debug("userinfo returned error: " + map.get("error"));
     throw new InvalidTokenException(accessToken);
  }
  return extractAuthentication(map);
}
Cuando utiliza varios proveedores, puede especificar diferentes opciones en un CustomUserInfoTokenServices y registrar diferentes clases de servicios similares en el método de declaración de filtro. Ahora tanto el Usuario como OAuth2Authentication pueden actuar como Principal. Dado que en UserService tomamos en cuenta de antemano la carga del usuario a través de los datos de Google, la aplicación funcionará para ambos tipos de usuarios. Modificamos el controlador de la página principal del proyecto para que redirija a los usuarios que iniciaron sesión usando OAuth2 a la página de notas.
@GetMapping("/")
public String index(Principal principal)
{
  if(principal != null)
  {
     return "redirect:/notes";
  }
  return "index";
}

Lanzamiento final del proyecto.

Después de pequeños cambios estéticos y añadiendo un botón de salida, llevamos a cabo el lanzamiento final del proyecto.
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 8
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 9
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 10
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 11
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 12
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 13
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 14
Introduzcamos el inicio de sesión regular por correo electrónico y OAuth2 en Spring Security usando el ejemplo del servicio de notas - 15
El usuario inicia sesión correctamente tanto a través del formulario habitual como a través de una cuenta de Google. ¡Esto es lo que queríamos! Espero que este artículo haya aclarado algunos puntos sobre la creación de una aplicación web, su protección con Spring Security y la combinación de diferentes métodos de inicio de sesión. Con el código completo del proyecto puedes
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION