Autenticación y autorización de Spring Security (1)

        En el artículo anterior, seguimos el mecanismo de seguridad predeterminado de Spring Security ; solo hay un usuario y un solo rol. En el desarrollo real, esto naturalmente no puede satisfacer la demanda. Este artículo configurará Spring Security con más profundidad e inicialmente usará el mecanismo de autorización.

1. Autenticación y autorización del modelo de base de datos por defecto:

1. Preparación de recursos:

        Primero, cree un nuevo paquete de controlador , cree tres controladores y cree algunas rutas de prueba en los controladores respectivamente. Los códigos de las tres clases son los siguientes:

@RestController
@RequestMapping("/admin/api")
public class AdminController {

	@GetMapping("/hello")
	public String hello() {
		return "hello admin";
	}
}
@RestController
@RequestMapping("/app/api")
public class AppController {

	@GetMapping("/hello")
	public String hello() {
		return "hello app";
	}
}
@RestController
@RequestMapping("/user/api")
public class UserController {

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

        Supongamos que el contenido en /admin/api es la API relacionada con la administración en segundo plano del sistema , el contenido en /app/api es la API para el acceso público al cliente y el contenido en /user/api/ está relacionado con la propia API de operación de datos del usuario ; obviamente, /admin/api debe tener privilegios de administrador para operar, y /user/api debe operarse después de que el usuario inicie sesión.

2. Configuración de autorización de recursos:

        Para poder acceder a la ruta anterior con normalidad, necesitamos modificar la clase de configuración  WebSecurityConfig , el código es el siguiente:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

	protected void configure(HttpSecurity http) throws Exception{
		http.authorizeRequests().
		antMatchers("/admin/api/**").hasRole("ADMIN").
		antMatchers("/user/api/**").hasRole("USER").
		antMatchers("/app/api/**").permitAll().
		anyRequest().authenticated().
		and().formLogin();
	}
}

        antMatchers() es un comparador de URL que toma patrones ANT . ¿Modo ANT a usar? Haga coincidir cualquier carácter único, use * para hacer coincidir 0 o cualquier número de caracteres y use ** para hacer coincidir 0 o más directorios. antMatchers("/admin/api/**") es equivalente a hacer coincidir todas las API en /admin/api/ . Aquí especificamos que solo se puede acceder cuando debe estar en el rol ADMIN , y /usuario/api/ es lo mismo. La API en /app/api/ llamará a permitAll() para revelar sus permisos.

        La configuración relacionada con la autorización no parece complicada, pero parece que falta algo. Ignóralo por ahora.

        Reinicie el servicio, intente acceder a localhost:8080/app/api/hello y la página imprimirá "hello app" , lo que verifica que el servicio en /app/api/ está realmente abierto al público. Luego visite localhost:8080/user/api/hello , esta vez necesita iniciar sesión. Intentamos ingresar el nombre de usuario y la contraseña definidos anteriormente en application.properties , después de iniciar sesión, la página imprime "hola usuario" . Sin embargo, no tenemos un usuario usuario , ¿por qué podemos acceder con éxito a la ruta? Para poder comprobar que no hay problema con el enlace de autorización, intentamos acceder a localhost:8080/admin/api/hello , y el contenido que aparece es el siguiente:

Se muestra un error 403          en la página , lo que indica que la autorización del usuario falló ( 401 significa que la autenticación del usuario falló). En otras palabras, esta visita ya pasó el proceso de autenticación, pero fue rechazada durante la autorización. No hay problema en el enlace de autenticación, porque el rol de usuario predeterminado de Spring Security es user .

        El código de estado HTTP ( Código de estado HTTP ) es una especificación definida por RFC 2616 para indicar el estado de una respuesta de solicitud HTTP , que consta de 3 dígitos. Por lo general, 2XX se usa para indicar que la operación es exitosa, 4XX se usa para indicar que la falla es causada por el cliente y 5XX se usa para indicar que el error es causado por el servidor.

3. Soporte multiusuario basado en memoria:

        Hasta ahora, todavía tenemos un solo usuario que puede iniciar sesión, ¿cómo presentar a varios usuarios? Es muy simple, solo necesitamos implementar un UserDetailsService personalizado , el código es el siguiente:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

	protected void configure(HttpSecurity http) throws Exception{
		http.authorizeRequests().
		antMatchers("/admin/api/**").hasRole("ADMIN").
		antMatchers("/user/api/**").hasRole("USER").
		antMatchers("/app/api/**").permitAll().
		anyRequest().authenticated().
		and().formLogin();
	}
	@Bean
	public UserDetailsService userDetailsService() {
		InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
		manager.createUser(User.withUsername("user").password("123").roles("USER").build());
		manager.createUser(User.withUsername("admin").password("123").roles("USER","ADMIN").build());
		return manager;
	}
}

        Agregue una anotación @bean y Spring Security podrá descubrirlo y usarlo . Spring Security admite datos de usuario de varias fuentes, incluida la memoria, bases de datos, LDAP , etc. Se abstraen como una interfaz UserDetailsService y cualquier objeto que implemente la interfaz UserDetailsService se puede utilizar como fuente de datos de autenticación. En este modo de diseño, Spring Security es particularmente flexible.

        InMemoryUserDetailsManager es una clase de implementación en la interfaz UserDetailsService . Almacena fuentes de datos de usuario en la memoria, lo que es muy útil en algunos sistemas que no necesitan introducir fuentes de datos pesadas, como bases de datos. Aquí simplemente llame a createUser() para generar dos usuarios y asignarles los roles correspondientes. Funcionará bien y reiniciará el servicio varias veces sin problemas. ¿Por qué enfatizar reiniciar el servicio varias veces? La respuesta se revelará más adelante.

4. Autenticación y autorización basada en el modelo de base de datos predeterminado:

        Además de InMemoryUserDetailsManager , Spring Security también proporciona otra clase de implementación de UserDetailsService : JdbcUserDetailsManager .

        JdbcUserDetailsManager nos ayuda a conectar bases de datos y Spring Security de la manera JDBC . Establece un modelo de base de datos predeterminado. Siempre que se siga este modelo, JdbcUserDetailsManager es incluso comparable a InMemoryUserDetailsManager en términos de simplicidad .

4.1 Preparación de la base de datos:

Introduzca las dependencias de la base de datos de jdbcmysql         en pom.xml , de la siguiente manera:

        <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>

        Luego configure los parámetros de conexión de la base de datos en application.properties .

spring.datasource.url = jdbc:mysql://localhost:3306/springDemo?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username = root
spring.datasource.password = Rfid123456

        El nombre de la base de datos conectada aquí es springDemo ( no habrá problema si driverClassName no está configurado , porque SpringBoot lo deducirá automáticamente en función de la URL ). El nombre de usuario y la contraseña son root y Rfid123456 respectivamente . Los lectores pueden modificarlo de acuerdo con la situación real Como se mencionó anteriormente, JdbcUserDetailsManager establece un modelo de base de datos predeterminado, que SpringSecurity define en /org/springframework/security/core/userdetails/jdbc/users.ddl .

        A continuación está la declaración de creación de la tabla, de la siguiente manera:

create database springDemo;
use springDemo;
create table users(
	username varchar(50) not null primary key,
	password varchar(500) not null,
	enabled boolean not null
);

create table authorities(
	username varchar(50) not null,
	authority varchar(50) not null,
	constraint fk_authorities_user foreign key(username) references users(username)
);
create unique index ix_auth_username on authorities(username,authority);

        JdbcUserDetailsManager necesita dos tablas, entre las cuales la tabla de usuarios se usa para almacenar el nombre de usuario, la contraseña y la información de disponibilidad, y la tabla de autoridades se usa para almacenar la relación correspondiente entre el nombre de usuario y su autoridad.

4.2 Implementación de la codificación:

        Construyamos una instancia de JdbcUserDetailsManager para permitir que Spring Security use la base de datos para administrar usuarios.

import org.apache.tomcat.jdbc.pool.DataSource;

@Autowired
private DataSource dataSource;

@Bean
public UserDetailsService userDetailsService() {
	JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
	manager.setDataSource(dataSource);
	manager.createUser(User.withUsername("user").password("123").roles("USER").build());
    manager.createUser(User.withUsername("admin").password("123").
        roles("USER","ADMIN").build());
	return manager;
}

        No hay mucha diferencia entre JdbcUserDetailsManager e InMemoryUserDetailsManager en términos de uso, excepto que hay un enlace adicional para establecer DataSource . Spring Security ejecuta los comandos establecidos a través de DataSource . Por ejemplo, la función createUser aquí en realidad ejecuta la siguiente instrucción SQL :

insert into users(username,password,enabled) values(?,?,?)

        Consulte el código fuente de JdbcUserDetailsManager para ver instrucciones SQL más bien definidas , como deleteUserSql , updateUserSql , etc. Estas son las formas de interacción real entre JdbcUserDetailsManager y la base de datos. Por supuesto, JdbcUserDetailsManager también nos permite personalizar estas sentencias SQL en casos especiales, si es necesario, basta con llamar al método setXxxSql correspondiente.

Ahora reinicie el servicio y vea qué datos genera Spring Security         en la base de datos , como se muestra en la figura a continuación.

        El campo de autoridad de la tabla de autoridades almacena los roles establecidos anteriormente, pero tendrá el prefijo "ROLE_" . Intentemos crear una cuenta de prueba a través del comando SQL .

insert into users values("test","123",1);
insert into authorities values("test","ROLE_USER");

        Borre el caché y use la cuenta de prueba para acceder al sistema. Se encuentra que se puede acceder a la ruta del usuario , pero no se puede acceder a la ruta del administrador , lo cual es consistente con el comportamiento esperado.

        Hasta ahora, todo funciona bien, pero tan pronto como reiniciamos el servicio, la aplicación arroja un error. Esto se debe a que cuando la tabla de usuarios crea una declaración, el campo de nombre de usuario es la clave principal y la clave principal es única y única. Sin embargo, después de reiniciar el servicio, el administrador y el usuario se crearán nuevamente , lo que hará que la base de datos informe un error. (Este problema no ocurre en fuentes de datos de memoria, porque después de reiniciar el servicio, se borrará el contenido en el campo de nombre de usuario ). Por lo tanto, si necesita generar algunos usuarios cuando se inicia el servicio, se recomienda determinar primero si existe el nombre de usuario. Como sigue:

import org.apache.tomcat.jdbc.pool.DataSource;

@Autowired
private DataSource dataSource;

@Bean
public UserDetailsService userDetailsService() {
	JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
	manager.setDataSource(dataSource);
    if(!manager.userExists("user")){
        manager.createUser(User.withUsername("user").password("123").
            roles("USER").build());
    }
    if(!manager.userExists("admin")) {
        manager.createUser(User.withUsername("admin").password("123").
            roles("USER","ADMIN").build());
    }
	return manager;
}

        En la página de inicio de sesión del formulario personalizado, la clase WebSecurityConfigurerAdapter define tres métodos configure() .

protected void configure(AuthenticationManagerBuilder auth) throws Exception {
	this.disableLocalConfigureAuthenticationBldr = true;
}

public void configure(WebSecurity web) throws Exception {

}

protected void configure(HttpSecurity http) throws Exception {
	http
		.authorizeRequests()
			.anyRequest().authenticated()
				.and()
		.formLogin().and()
		.httpBasic();
}

        Solo usamos un parámetro http para recibir el método de configuración del objeto HttpSecurity . Los otros dos parámetros también tienen sus propios propósitos, entre ellos, la configuración de AuthenticationManagerBuilder también nos permite configurar usuarios de autenticación.

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
	
	protected void configure(HttpSecurity http) throws Exception{
		http.authorizeRequests().
		antMatchers("/admin/api/**").hasRole("ADMIN").
		antMatchers("/user/api/**").hasRole("USER").
		antMatchers("/app/api/**").permitAll().
		anyRequest().authenticated().
		and().formLogin();
	}
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication()
			.withUser("user").password("123").roles("user")
			.and()
			.withUser("admin").password("123").roles("admin");
	}
}

        Los métodos de uso son similares, por lo que no entraré en detalles aquí.

        Cuando se utiliza el modelo de base de datos predeterminado de Spring Security para tratar con varios sistemas de usuarios, es inevitable que la flexibilidad no sea buena. Especialmente cuando se integra Spring Security en un sistema existente , los datos de usuario originales se han corregido y, obviamente, no vale la pena modificarlos a nivel de la base de datos para adaptarlos a Spring Security . El potente y flexible Spring Security mejora esto.

Supongo que te gusta

Origin blog.csdn.net/xhf852963/article/details/121946119
Recomendado
Clasificación