Directorio de artículos
1. Autorización
La denominada autorización significa que si un usuario quiere acceder a un determinado recurso, tenemos que comprobar si el usuario tiene tal permiso, si lo tiene, entonces puede acceder, si no, no está permitido.
Dos, prepárate para probar a los usuarios
Debido a que aún no nos hemos conectado a la base de datos, el usuario de prueba todavía está configurado en función de la memoria.
Con base en los usuarios de prueba de configuración de memoria, tenemos dos métodos, el primero es el método de configuración que usamos en los artículos anteriores de esta serie, como sigue:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中进行配置
auth.inMemoryAuthentication()
.withUser("yolo")
.password("123").roles("admin")
.and()
.withUser("nlcs")
.password("123")
.roles("user");
}
Este es un método de configuración.
Dado que Spring Security admite una variedad de fuentes de datos, como memoria, bases de datos, LDAP, etc., estas diferentes fuentes de datos se encapsulan en una UserDetailService
interfaz común , cualquier objeto que implemente esta interfaz puede usarse como fuente de datos de autenticación.
De este modo se puede reescribir WebSecurityConfigurerAdapter
de userDetailsService
proporcionar un método para UserDetailService
ejemplo dispuesto además una pluralidad de usuarios:
@Override
@Bean
protected UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("yolo").password("123").roles("admin").build());
manager.createUser(User.withUsername("nlcs").password("123").roles("user").build());
return manager;
}
Tres, prepárate para probar la interfaz
El usuario de prueba está listo y luego preparamos tres interfaces de prueba. como sigue:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/admin/hello")
public String admin() {
return "admin";
}
@GetMapping("/user/hello")
public String user() {
return "user";
}
}
Para estas tres interfaces de prueba, nuestro plan es así:
(1) Es
/hello
una interfaz a la que puede acceder cualquier persona
(2) Es/admin/hello
una interfaz a la que solo puede acceder una persona con una identidad de administrador
(3)/user/hello
Una interfaz a la que puede acceder una persona con una identidad de usuario
(4) Todos los usuarios pueden acceder a los recursos, el administrador puede acceso
Tenga en cuenta que la cuarta especificación significa que todas las personas con identidad de administrador automáticamente tienen identidad de usuario
Cuatro, configuración
A continuación configuramos los permisos de las reglas de bloqueo, en el configure(HttpSecurity http)
método de Spring Security , el código es el siguiente:
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated()
.and()
...
...
Para las reglas de coincidencia aquí, usamos símbolos de coincidencia de ruta de estilo Ant. Los símbolos de coincidencia de ruta de estilo Ant se utilizan ampliamente en la familia Spring, y sus reglas de coincidencia también son muy simples:
El significado de la configuración anterior es:
(1) Si la solicitud satisface un
/admin/**
formato de ruta , el usuario debe tener un rol de administrador.
(2) satisfecho si la solicitud es un/user/**
formato de ruta , el usuario debe tener el rol de usuario.
(3) Se puede acceder a las rutas de solicitud restantes en otros formatos solo después de la autenticación (inicio de sesión).
Tenga en cuenta que el orden de las tres reglas configuradas en el código es muy importante. Similar a Shiro, Spring Security también coincide de arriba a abajo cuando coincide. Una vez que coincida, no seguirá coincidiendo.Así que el orden de las reglas de interceptación no se puede escribir mal
Por otro lado, si fuerza a que anyRequest se coloque antes de antMatchers, así:
http.authorizeRequests()
.anyRequest().authenticated()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
.and()
En este punto, cuando se inicia el proyecto, se informará un error y se le indicará que no se puede agregar antMatchers después de anyRequest:
Esto está bien entendido semánticamente, anyRequest
otras solicitudes ya están incluidas y no tiene ningún sentido si se configuran otras solicitudes después.
Entendido semánticamente, anyRequest
debe colocarse al final, indicando cómo manejar las solicitudes restantes además de las reglas de interceptación anteriores.
En las reglas de bloqueo de la clase de configuración AbstractRequestMatcherRegistry
, podemos ver algunos códigos de la siguiente manera (sección Fuente):
public abstract class AbstractRequestMatcherRegistry<C> {
private boolean anyRequestConfigured = false;
public C anyRequest() {
Assert.state(!this.anyRequestConfigured, "Can't configure anyRequest after itself");
this.anyRequestConfigured = true;
return configurer;
}
public C antMatchers(HttpMethod method, String... antPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.antMatchers(method, antPatterns));
}
public C antMatchers(String... antPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
}
protected final List<MvcRequestMatcher> createMvcMatchers(HttpMethod method,
String... mvcPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure mvcMatchers after anyRequest");
return matchers;
}
public C regexMatchers(HttpMethod method, String... regexPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure regexMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.regexMatchers(method, regexPatterns));
}
public C regexMatchers(String... regexPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure regexMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.regexMatchers(regexPatterns));
}
public C requestMatchers(RequestMatcher... requestMatchers) {
Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest");
return chainRequestMatchers(Arrays.asList(requestMatchers));
}
}
A partir de este código fuente, podemos ver que antes de cualquier regla de interceptación (incluido anyRequest en sí), primero determinará si se ha configurado anyRequest. Si está configurado, se lanzará una excepción y el sistema no se iniciará.
Para que todos entiendan por qué anyRequest debe colocarse en último lugar
Cinco, comienza la prueba
A continuación, comenzamos el proyecto para probarlo.
Después de que el proyecto se haya lanzado con éxito, primero iniciamos sesión como yolo:
Después de iniciar sesión correctamente, visite las tres interfaces / hello, / admin / hello y / user / hello respectivamente, entre las cuales:
(1)
/hello
Debido a que puede acceder después de iniciar sesión, se accede correctamente a esta interfaz.
(2) Se/admin/hello
requiere la identidad de administrador, por lo que el acceso falla.
(3) Se/user/hello
requiere la identidad del usuario, por lo que el acceso es exitoso.
Inicie sesión en nlcs de la misma manera.
Seis, herencia de roles
Como se mencionó anteriormente, todos los recursos a los que el usuario puede acceder pueden ser accedidos por el administrador Obviamente, nuestro código actual aún no tiene tal función.
Para implementar todos los recursos a los que el usuario puede acceder, el administrador puede acceder a ellos. Esto involucra otro punto de conocimiento, llamadoHerencia de roles
Esto es muy útil en el desarrollo real.
El nivel superior puede tener todos los permisos del nivel inferior. Si se usa la herencia de roles, esta función es muy fácil de implementar. Solo necesitamos agregar el siguiente código a SecurityConfig para configurar la relación de herencia de roles:
@Bean
RoleHierarchy roleHierarchy() {
RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
hierarchy.setHierarchy("ROLE_admin > ROLE_user");
return hierarchy;
}
Tenga en cuenta que en la configuración, debe agregar manualmente el ROLE_
prefijo de carácter . La configuración anterior significa ROLE_admin
tener ROLE_user
permiso automáticamente .
Una vez completada la configuración, reinicie el proyecto, esta vez descubrimos que yolo también puede acceder a /user/hello
esta interfaz