Spring Security: 1 [Descripción general de la gestión de permisos, autenticación y autorización de Spring Security]


Seguridad de primavera

objetivo de aprendizaje

  • Comprender los conceptos de gestión de derechos
  • ¿Qué problemas se pueden resolver dominando SpringSecurity y por qué deberíamos aprenderlo?
  • Domine cómo autenticarse con Spring Security
  • Domine cómo Spring Security realiza la autorización
  • Comprender los principios subyacentes de autenticación y autorización.
  • Master integrando autenticación y autorización en proyectos
  • Maestro JWT

1. Descripción general de la gestión de derechos

La gestión de permisos generalmente significa que, de acuerdo con las reglas de seguridad o las políticas de seguridad establecidas por el sistema, los usuarios pueden acceder y solo pueden acceder a los recursos a los que están autorizados. La gestión de permisos aparece en casi cualquier sistema, siempre que exista un sistema con usuarios y contraseñas. Mucha gente suele confundir conceptos como "autenticación de identidad de usuario", "cifrado de contraseña" y "gestión del sistema" con el concepto de gestión de derechos.

1.1.¿Qué es la certificación?

Al ingresar a la era de Internet móvil, todos usan sus teléfonos móviles todos los días. El software más utilizado incluye WeChat, Alipay, Toutiao, etc. Tomemos WeChat como ejemplo para ilustrar los conceptos básicos relacionados con la autenticación. Antes de usar WeChat por primera vez, debe registrarse como usuario de WeChat e ingresar su número de cuenta y contraseña para iniciar sesión en WeChat. El proceso de iniciar sesión en WeChat ingresando su número de cuenta y contraseña es autenticación.

¿Por qué es necesario autenticar el sistema?

La autenticación es para proteger la privacidad de los datos y los recursos del sistema. Solo los usuarios con identidad legal pueden acceder a los recursos del sistema.

1.2 ¿Qué es la autorización?

Hay muchos recursos en una plataforma. Diferentes usuarios pueden operar diferentes recursos y necesitan que se les concedan diferentes permisos. Sólo cuando se les conceden pueden operar. Esto es autorización.

¿Por qué autorizar?

La autenticación es para garantizar la legitimidad de la identidad del usuario y la autorización es para dividir los datos privados de una manera más detallada. La autorización ocurre después de que se pasa la autenticación y controla la capacidad de diferentes usuarios para acceder a diferentes recursos.

1.3 Modelo de datos autorizado RBAC

El control de acceso basado en roles (RBAC) en la gestión de derechos funcionales se utiliza con mayor frecuencia en la gestión de derechos.

Insertar descripción de la imagen aquí

Cuando necesitamos utilizar la gestión de permisos en un proyecto, podemos optar por implementarlo nosotros mismos (el sistema RBAC implementado en el curso anterior), o podemos optar por utilizar un marco implementado por terceros para implementarlo. mejor depende de que todos tengan necesidades específicas en el proyecto.

Funciones necesarias para implementar el sistema de gestión de derechos:

1.权限管理(自定义权限注解/加载权限)
2.角色管理(新增/编辑/删除/关联权限)
3.用户管理(新增/编辑/删除/关联用户)
4.登录功能(定义登录拦截器/登录逻辑实现/登出功能)
5.权限拦截(定义权限拦截器/拦截逻辑实现)
1.3.1 Control de acceso basado en roles

El control de acceso basado en roles de RBAC (control de acceso basado en roles) está autorizado por rol. Por ejemplo, si el rol del sujeto es gerente general, puede consultar informes de operación empresarial, consultar información salarial de los empleados, etc. El proceso de control de acceso es el siguiente :

Insertar descripción de la imagen aquí

Según la lógica de juicio en la figura anterior, el código de autorización se puede expresar de la siguiente manera:

if(主体.hasRole("总经理角色id")){
    
    
查询工资
}

Si los roles requeridos para la consulta salarial en la figura anterior cambian a gerente general y gerente de departamento, entonces la lógica de juicio debe modificarse para "determinar si el rol del usuario es gerente general o gerente de departamento". El código modificado es el siguiente:

if(主体.hasRole("总经理角色id") || 主体.hasRole("部门经理角色id")){
    
    
查询工资
}

Según el ejemplo anterior, se descubre que cuando es necesario modificar los permisos de una función, es necesario modificar el código relacionado con la autorización y la escalabilidad del sistema es deficiente.

1.3.2 Control de acceso basado en recursos

El control de acceso basado en recursos RBAC (control de acceso basado en recursos) se autoriza en función de los recursos (o permisos). Por ejemplo, los usuarios deben tener permiso de consulta de salario antes de poder consultar la información salarial de los empleados, etc. El proceso de control de acceso es el siguiente:

Insertar descripción de la imagen aquí

Según el juicio de la figura anterior, el código de autorización se puede expresar como:

if(主体.hasPermission("查询工资权限标识")){
    
    
查询工资
}

Ventajas: La identificación del permiso para la consulta de salario se define cuando se diseña el sistema. Incluso si los roles requeridos para la consulta de salario cambian a gerente general y gerente de departamento, no es necesario modificar el código de autorización y el sistema es altamente escalable.

1.4 Marco de gestión de derechos

¿Qué problemas puede ayudarnos a resolver el marco en el sistema de gestión de derechos?

Función Qué puede hacer el marco de permisos
gestión de autoridad ×
gestión de roles ×
Gestión de usuarios ×
Función de inicio de sesión √ (Cifrado de contraseña, código de verificación, recuérdame)
Interceptación de permisos √ (Muchos interceptores integrados, que proporcionan etiquetas/anotaciones/métodos de programación para la autenticación de permisos)

Aquí presentamos dos marcos de gestión de derechos comúnmente utilizados:

1.4.1 Apache Shiro

Apache Shiro es un marco de seguridad Java potente y fácil de usar. Cada vez más personas utilizan Apache Shiro. Puede implementar funciones como autenticación, autorización, contraseña y gestión de sesiones.

1.4.2 Seguridad de primavera

Spring Security también es un marco de gestión de derechos de seguridad popular y está estrechamente integrado con Spring.

1.4.3 Comparación entre Shiro y Spring Security

La mayor diferencia entre Shiro y Spring Security es que Shiro es un módulo independiente, que es flexible de usar, pero resultará en un diseño intrusivo; mientras que Spring Security se basa en el mecanismo proxy de filtro de Spring y está vinculado a Spring, que no es lo suficientemente flexible. pero no es intrusivo. de. Además, tanto Shiro como Spring Security admiten el cifrado de contraseñas, Shiro admite la gestión de sesiones y Spring Security proporciona protección contra vulnerabilidades comunes (como CSRF).

2. Autenticación y autorización de Spring Security

Spring Security es un marco de seguridad que proporciona soluciones de control de acceso de seguridad declarativa para sistemas de aplicaciones empresariales basados ​​en Spring. Debido a que es miembro del ecosistema Spring, se revisa y actualiza constantemente junto con todo el ecosistema Spring. Es muy sencillo agregar seguridad Spring al proyecto de arranque Spring. El uso de Spring Security reduce la necesidad de escribir una gran cantidad de código duplicado. para el control de seguridad del sistema empresarial.

2.1 Preparación del entorno

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <!--spring security 组件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--web 组件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- test 组件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>

Crear application.properties y clases de inicio

clase de inicio

@SpringBootApplication
public class App {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(App.class,args);
    }
}

Crear controlador

@RestController
public class HelloController {
    
    
    @RequestMapping("/hello")
    public String hello(String name){
    
    
        return "操作成功";
    }
}

Inicie el proyecto:
La consola de observación generará una contraseña, la cuenta predeterminada es usuario.

Using generated security password: a6c875c9-9b2e-4df9-a517-56c571258b01

Acceda a los recursos en el navegador: http://localhost:8080/hello?name=zhangsan, encontrará que el acceso a los recursos está bloqueado. SpringSecurity proporciona una página de autenticación de forma predeterminada y no requiere desarrollo adicional.

2.2 Certificación

2.2.1 Configuración de seguridad

Spring Security proporciona inicio de sesión, cierre de sesión, administración de sesión y otras funciones de autenticación con nombre de usuario y contraseña, que solo deben configurarse para su uso.
Defina WebSecurityConfig en el paquete de configuración. La configuración de seguridad incluye: información de usuario, codificador de contraseña y mecanismo de interceptación de seguridad.

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    
//配置用户信息服务
    @Bean
    public UserDetailsService userDetailsService() {
    
    
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1").build());
        manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build());
        return manager;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
    
    
        return NoOpPasswordEncoder.getInstance();
    }

    //配置安全拦截机制
    protected void configure(HttpSecurity http) throws Exception {
    
    
        http
                //配置权限
                .authorizeRequests()
                .antMatchers("/hello").permitAll()
                .anyRequest().authenticated()
         http.formLogin()
                //登录成功后调整页面
                successForwardUrl("/main");
    }
}

controlador:

@RequestMapping("/main")
public String main(String name){
    
    
    return "redirect:/main.html";
}

principal.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
我是主界面
</body>
</html>

En el método userDetailsService(), devolvemos un UserDetailsService al contenedor Spring, que Spring Security utilizará para obtener información del usuario. Usamos temporalmente la clase de implementación InMemoryUserDetailsManager y creamos dos usuarios, zhangsan y lisi, respectivamente
, y configuramos contraseñas y permisos.

En configure(), configuramos reglas de interceptación de seguridad a través de HttpSecurity, que incluyen lo siguiente:
(1) Se permite el recurso de coincidencia de URL /hello.
(2) Otras URL requieren autenticación.
(3) Habilite la autenticación de envío de formulario. El inicio de sesión exitoso saltará a la ruta /principal.

2.2.2 Interfaz de inicio de sesión personalizada

Crear una interfaz de inicio de sesión en estática

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org/" lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户登录</title>
</head>
<body>
<h1>用户登录</h1>
<form action="/login" method="post">
    用户名:<input type="text" name="username"> <br>
    密码:<input type="text" name="password"><br>
    <input type="submit" value="登录">
</form>
</body>
</html>

Agregar a la clase de configuración:

 protected void configure(HttpSecurity http) throws Exception {
    
    
        http
                //配置权限
                .authorizeRequests()
                .antMatchers("/hello").authenticated()
                .anyRequest().permitAll()
           .and()
                //配置表单登录
                .formLogin().
                    loginPage("/login.html"). 
                    loginProcessingUrl("/login").
                    successForwardUrl("/main");
    }

En configure(), configuramos reglas de interceptación de seguridad a través de HttpSecurity, que incluyen lo siguiente:
(1) La interfaz de inicio de sesión es login.html en modo estático
(2) Formule la ruta URL para el inicio de sesión del formulario

Al acceder, verá la siguiente interfaz:

Insertar descripción de la imagen aquí

2.2.3 resolución del problema 403

Ingrese su cuenta y contraseña, haga clic en iniciar sesión e informe un error:

Insertar descripción de la imagen aquí

Problema:
para evitar la aparición de CSRF (falsificación de solicitudes entre sitios), la seguridad de Spring restringe la mayoría de los métodos excepto get.

Insertar descripción de la imagen aquí

Solución :
Proteger el control CSRF, es decir, la seguridad de Spring ya no restringe CSRF.
Configurar WebSecurityConfig

@Override
protected void configure(HttpSecurity http) throws Exception {
    
    
  //屏蔽CSRF控制,即spring security不再限制CSRF      
  http.csrf().disable() 
...
}
2.2.4 Modificar el nombre del parámetro de inicio de sesión

Los nombres predeterminados de los parámetros de cuenta y contraseña son: nombre de usuario, contraseña, que deben corresponder al fondo antes de que se pueda realizar el inicio de sesión normal. Por supuesto, Spring Security también brinda la capacidad de modificar los nombres de los parámetros.

Configuración:

  .formLogin().
   							//自定义登录页面
                loginPage("/loginPage").
               //当发现/login时认为是登录,必须和表单提交的地址一样。
                loginProcessingUrl("/login").
                //登录成功后调整页面
                successForwardUrl("/main").
                //登录失败后跳转页面
                .failureForwardUrl("/toError");
                //自定义账号密码参数名
                usernameParameter("uname").
                passwordParameter("passwd");

Método de prueba: modifique el nombre del parámetro en la interfaz y vea si puede iniciar sesión más tarde. Si no puede iniciar sesión, agregue la configuración y reinicie para iniciar sesión. Si el inicio de sesión es exitoso, verifique que la configuración surta efecto.

2.2.5 Configuración de cierre de sesión

Spring Security implementa la salida de cierre de sesión y el acceso/cierre de sesión de forma predeterminada. Como era de esperar, Spring también realiza la función de salida por nosotros.

También puede personalizar la operación de inicio de sesión en Spring Security,
la configuración es la siguiente:

.and() 
.logout() 
.logoutUrl("/logout")
.logoutSuccessUrl("/logoutSuccess");

código del controlador

@RequestMapping("/logoutSuccess")
public String logout1(){
    return "logout";
}

interfaz:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
登出界面
</body>
</html>
2.2.6 Controlador de inicio de sesión personalizado

La capa inferior de SuccessForwardUrl que inicia sesión correctamente es la acción de reenvío de solicitudes, que no se puede utilizar en proyectos donde los extremos frontal y posterior están separados.

Código:

public class MyAuthenticationSuccessHandler
        implements   {
    
    
    private String url;
    public MyAuthenticationSuccessHandler(String url) {
    
    
        this.url = url;
    }
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication)
            throws IOException, ServletException {
    
    
        User user = (User)authentication.getPrincipal();
        System.out.println(user.getUsername());
        System.out.println(user.getPassword());
        System.out.println(user.getAuthorities());
        response.sendRedirect(this.url);
    }
}

Configuración:

   http .formLogin().
                    loginPage("/login.html").
                    loginProcessingUrl("/login").
                    successHandler(new SuccessAuthenticationSuccessHandler("http://www.baidu.com")).

SuccessHandler: cuando el inicio de sesión sea exitoso, se entregará a nuestro propio procesador definido para su procesamiento.

2.2.7 Controlador de errores de inicio de sesión personalizado

Código:

public class FailAuthenticationFailureHandler implements AuthenticationFailureHandler {
    
    
    private String url;

    public FailAuthenticationFailureHandler(String url) {
    
    
        this.url = url;
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
    
    
        response.sendRedirect(url);

    }
}

Configuración:

http.formLogin().
                    loginPage("/login.html").
                    loginProcessingUrl("/login").
                    successHandler(new SuccessAuthenticationSuccessHandler("http://www.baidu.com")).
                    failureHandler(new FailAuthenticationFailureHandler("http://www.baidu.com")).

FailureHandler: cuando falla el inicio de sesión, lo maneja nuestro propio procesador definido.

2.3 Autorización

2.3.1 Autorización del modo de configuración

La implementación de la autorización requiere interceptar y verificar el acceso del usuario para verificar si los permisos del usuario pueden operar los recursos especificados. Spring Security proporciona métodos de implementación de autorización de forma predeterminada.

Agregue /r/r1 o /r/r2 a LoginController

   @GetMapping("/r/r1")
    public String r1() {
    
    
        return " 访问资源1";
    }

    @GetMapping("/r/r2")
    public String r2() {
    
    
        return " 访问资源2";
    }

Configure reglas de autorización en la clase de configuración de seguridad WebSecurityConfifig.java:

.antMatchers("/r/r1").hasAuthority("p1") .antMatchers("/r/r2").hasAuthority("p2")

Explicación de la configuración:

  • .antMatchers("/r/r1").hasAuthority("p1") significa: acceder a la URL del recurso /r/r1 requiere permiso p1.
  • .antMatchers("/r/r2").hasAuthority("p2") significa: la URL que accede al recurso /r/r2 debe tener p2

prueba:

1. Inicie sesión correctamente

2. Acceda a /r/r1 y /r/r2. Si tiene permiso, acceda normalmente, de lo contrario devuelva 403 (Acceso denegado)

Nota: Este método debe configurarse en SpringSecurityConfig, que tiene ciertos defectos. Si hay cientos de interfaces en segundo plano, cada una de las cuales debe configurarse en este método, será particularmente confuso. SpringSecurity también proporciona otro método. El método de anotación se usa con más frecuencia. Por supuesto, el uso de más anotaciones no significa que el método de anotación definitivamente se usará en los proyectos que salimos a hacer.

NOTA: El orden de las reglas es importante ya que primero se deben escribir reglas más específicas.

Por ejemplo:

.antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/admin/login").permitAll()

También se interceptará la escritura /admin/login de esta manera.

El orden debe invertirse

.antMatchers("/admin/login").permitAll() .antMatchers("/admin/**").hasRole("ADMIN")
2.3.2 Configuraciones comunes

Los métodos comúnmente utilizados para proteger las URL incluyen:

autenticado() protege la URL y requiere el inicio de sesión del usuario

permitAll() especifica que no es necesario proteger la URL, aplicaciones generales y archivos de recursos estáticos

hasRole(Rol de cadena) restringe el acceso a un único rol, el rol se incrementará en "ROLE_", por lo que "ADMIN" se comparará con "ROLE_ADMIN".

hasAuthority(Autoridad de cadena) restringe el acceso a una única autoridad

**hasAnyRole(String… roles)** permite el acceso de múltiples roles.

hasAnyAuthority(String… autoridades) permite el acceso de múltiples autoridades.

acceso (atributo de cadena) Este método utiliza expresiones SpEL, por lo que se pueden crear restricciones complejas.

hasIpAddress(String ipaddressExpression) restringe direcciones IP o subredes

2.3.3 Autorización de anotación

Ahora que dominamos cómo usar http.authorizeRequests () para autorizar recursos web, a partir de Spring Security versión 2.0, admite la seguridad de los métodos de la capa de servicio. En esta sección, aprenderemos tres tipos de anotaciones: @PreAuthorize, @PostAuthorize y @Secured.

Podemos habilitar la seguridad basada en anotaciones utilizando la anotación @EnableGlobalMethodSecurity en cualquier instancia de @Configuration.

Lo siguiente habilitará la anotación @Secured de Spring Security.

Configuración:

@EnableGlobalMethodSecurity(securedEnabled = true)

Código de respuesta:

@GetMapping("/r/r1")
@Secured("ROLE_HR")
@ResponseBody
public String r1() {
    
    
    return " 访问资源1";
}

@GetMapping("/r/r2")
@ResponseBody
@Secured("ROLE_ADMIN")
public String r2() {
    
    
    return " 访问资源2";
}

Nota: @Secured se utiliza generalmente para el control de acceso basado en roles.

Lo siguiente habilitará la anotación @PreAuthorize de Spring Security.

Configuración:

@EnableGlobalMethodSecurity(prePostEnabled = true)

Código java correspondiente:

    @PreAuthorize("hasAnyAuthority('p1')")
    @GetMapping(value = "/r/r1")
    public String r1() {
    
    
        return " 访问资源1";
    }

    @GetMapping(value = "/r/r2")
    @PreAuthorize("hasAnyAuthority('p2')")
    public String r2() {
    
    
        return " 访问资源2";
    }

Nota: @PreAuthorize generalmente se basa en el control de acceso a permisos y se usa con más frecuencia.

Supongo que te gusta

Origin blog.csdn.net/m0_52896752/article/details/132904967
Recomendado
Clasificación