Spring Security : 1 [Présentation de la gestion des autorisations, de l'authentification et de l'autorisation Spring Security]


Sécurité du printemps

objectif d'apprentissage

  • Comprendre les concepts de gestion des droits
  • Quels problèmes peuvent être résolus en maîtrisant SpringSecurity et pourquoi devrions-nous l'apprendre ?
  • Maîtrisez comment vous authentifier avec Spring Security
  • Maîtrisez comment Spring Security effectue l'autorisation
  • Comprendre les principes sous-jacents de l’authentification et de l’autorisation
  • Master intégrant l'authentification et l'autorisation dans les projets
  • Maître JWT

1. Aperçu de la gestion des droits

La gestion des autorisations signifie généralement que, selon les règles de sécurité ou les politiques de sécurité définies par le système, les utilisateurs peuvent accéder et ne peuvent accéder qu'aux ressources pour lesquelles ils sont autorisés. La gestion des autorisations apparaît dans presque tous les systèmes, à condition qu'il existe un système avec des utilisateurs et des mots de passe. De nombreuses personnes confondent souvent des concepts tels que « authentification de l'identité de l'utilisateur », « cryptage des mots de passe » et « gestion du système » avec le concept de gestion des droits.

1.1.Qu'est-ce que la certification

En entrant dans l'ère de l'Internet mobile, tout le monde utilise son téléphone portable tous les jours. Les logiciels couramment utilisés incluent WeChat, Alipay, Toutiao, etc. Prenons WeChat comme exemple pour illustrer les concepts de base liés à l'authentification. Avant d'utiliser WeChat pour la première fois, vous devez vous inscrire en tant qu'utilisateur WeChat et saisir votre numéro de compte et votre mot de passe pour vous connecter à WeChat. Le processus de connexion à WeChat en saisissant votre numéro de compte et votre mot de passe constitue une authentification.

Pourquoi le système doit-il être authentifié ?

L'authentification vise à protéger la confidentialité des données et des ressources du système. Seuls les utilisateurs ayant une identité légale peuvent accéder aux ressources du système.

1.2 Qu'est-ce qu'une autorisation ?

Il existe de nombreuses ressources sur une plate-forme. Différents utilisateurs peuvent exploiter différentes ressources et doivent se voir accorder des autorisations différentes. Ce n'est que lorsqu'elles sont accordées qu'ils peuvent opérer. Il s'agit d'une autorisation.

Pourquoi autoriser ?

L'authentification vise à garantir la légitimité de l'identité de l'utilisateur, et l'autorisation consiste à diviser les données privées de manière plus fine. L'autorisation se produit une fois l'authentification réussie et contrôle la capacité des différents utilisateurs à accéder à différentes ressources.

1.3 Modèle de données autorisé RBAC

Le contrôle d'accès basé sur les rôles (RBAC) dans la gestion des droits fonctionnels est le plus couramment utilisé dans la gestion des droits.

Insérer la description de l'image ici

Lorsque nous devons utiliser la gestion des autorisations dans un projet, nous pouvons choisir de l'implémenter nous-mêmes (le système RBAC implémenté dans le cours précédent), ou nous pouvons choisir d'utiliser un framework tiers implémenté pour l'implémenter. mieux dépend de chacun a des besoins spécifiques dans le projet.

Fonctions nécessaires à la mise en œuvre du système de gestion des droits :

1.权限管理(自定义权限注解/加载权限)
2.角色管理(新增/编辑/删除/关联权限)
3.用户管理(新增/编辑/删除/关联用户)
4.登录功能(定义登录拦截器/登录逻辑实现/登出功能)
5.权限拦截(定义权限拦截器/拦截逻辑实现)
1.3.1 Contrôle d'accès basé sur les rôles

Le contrôle d'accès basé sur les rôles RBAC (Role-Based Access Control) est autorisé par rôle. Par exemple, si le sujet est directeur général, il peut interroger les rapports d'exploitation de l'entreprise, interroger les informations sur les salaires des employés, etc. Le processus de contrôle d'accès est le suivant :

Insérer la description de l'image ici

Selon la logique de jugement de la figure ci-dessus, le code d'autorisation peut être exprimé comme suit :

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

Si les rôles requis pour la requête de salaire dans la figure ci-dessus deviennent directeur général et chef de service, alors la logique de jugement doit être modifiée pour « déterminer si le rôle de l'utilisateur est directeur général ou chef de service ». Le code modifié est le suivant :

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

Selon l'exemple ci-dessus, il s'avère que lorsque les autorisations d'un rôle doivent être modifiées, le code lié à l'autorisation doit être modifié et l'évolutivité du système est faible.

1.3.2 Contrôle d'accès basé sur les ressources

Le contrôle d'accès basé sur les ressources RBAC (Resource-Based Access Control) est autorisé en fonction des ressources (ou des autorisations). Par exemple, les utilisateurs doivent disposer d'une autorisation de requête de salaire avant de pouvoir interroger les informations sur le salaire des employés, etc. Le processus de contrôle d'accès est le suivant :

Insérer la description de l'image ici

Sur la base du jugement de la figure ci-dessus, le code d'autorisation peut être exprimé comme suit :

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

Avantages : L'identification des autorisations pour la requête de salaire est définie lors de la conception du système. Même si les rôles requis pour la requête de salaire changent en directeur général et chef de service, il n'est pas nécessaire de modifier le code d'autorisation et le système est hautement évolutif.

1.4 Cadre de gestion des droits

Quels problèmes le cadre peut-il nous aider à résoudre dans le système de gestion des droits ?

Fonction Ce que le cadre d'autorisations peut faire
gestion des autorités ×
gestion des rôles ×
Gestion des utilisateurs ×
Fonction de connexion √ (Cryptage du mot de passe, code de vérification, souvenez-vous de moi)
Interception des autorisations √ (De nombreux intercepteurs intégrés, fournissant des balises/annotations/méthodes de programmation pour l'authentification des autorisations)

Nous présentons ici deux cadres de gestion des droits couramment utilisés :

1.4.1 Apache Shiro

Apache Shiro est un framework de sécurité Java puissant et facile à utiliser. De plus en plus de personnes utilisent Apache Shiro. Il peut implémenter des fonctions telles que l'authentification, l'autorisation, la gestion des mots de passe et des sessions.

1.4.2 Sécurité du printemps

Spring Security est également un cadre de gestion des droits de sécurité populaire, et il est étroitement intégré à Spring.

1.4.3 Comparaison entre Shiro et Spring Security

La plus grande différence entre Shiro et Spring Security est que Shiro est un module indépendant, flexible à utiliser, mais qui entraînera une conception intrusive ; tandis que Spring Security repose sur le mécanisme proxy de filtre de Spring et est lié à Spring, ce qui n'est pas assez flexible. mais n'est pas intrusif. De plus, Shiro et Spring Security prennent en charge le cryptage des mots de passe, Shiro prend en charge la gestion des sessions et Spring Security offre une protection contre les vulnérabilités courantes (telles que CSRF).

2. Authentification et autorisation Spring Security

Spring Security est un cadre de sécurité qui fournit des solutions de contrôle d'accès de sécurité déclarative pour les systèmes d'applications d'entreprise basés sur Spring. Parce qu'il est membre de l'écosystème Spring, il est constamment révisé et mis à niveau avec l'ensemble de l'écosystème Spring. Il est très simple d'ajouter la sécurité Spring au projet de démarrage Spring. L'utilisation de Spring Security réduit le besoin d'écrire beaucoup de code en double. pour le contrôle de la sécurité des systèmes d'entreprise.

2.1 Préparation de l'environnement

<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>

Créer application.properties et classes de démarrage

Cours de démarrage

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

CréerContrôleur

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

Démarrer le projet :
La console d'observation générera un mot de passe. Le compte par défaut est utilisateur.

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

Accédez aux ressources dans le navigateur : http://localhost:8080/hello?name=zhangsan, vous constaterez que l'accès aux ressources est bloqué. SpringSecurity fournit une page d'authentification par défaut et aucun développement supplémentaire n'est requis.

2.2 Attestation

2.2.1 Configuration de la sécurité

Spring Security fournit un nom d'utilisateur et un mot de passe pour la connexion, la déconnexion, la gestion de session et d'autres fonctions d'authentification, qui doivent uniquement être configurées pour être utilisées.
Définissez WebSecurityConfig sous le package de configuration. La configuration de la sécurité comprend : les informations utilisateur, l'encodeur de mot de passe et le mécanisme d'interception de sécurité.

@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");
    }
}

manette:

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

main.html

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

Dans la méthode userDetailsService(), nous renvoyons un UserDetailsService au conteneur Spring, que Spring Security utilisera pour obtenir des informations sur l'utilisateur. Nous utilisons temporairement la classe d'implémentation InMemoryUserDetailsManager, créons respectivement deux utilisateurs, zhangsan et lisi,
et définissons les mots de passe et les autorisations.

Dans configure(), nous définissons des règles d'interception de sécurité via HttpSecurity, qui incluent les éléments suivants :
(1) La ressource de l'URL correspondant à /hello est autorisée.
(2) Les autres URL nécessitent une authentification.
(3) Activez l'authentification de soumission de formulaire. Une connexion réussie passera au chemin /main.

2.2.2 Interface de connexion personnalisée

Créer une interface de connexion en statique

<!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>

Ajouter à la classe de configuration :

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

Dans configure(), nous définissons des règles d'interception de sécurité via HttpSecurity, qui incluent les éléments suivants :
(1) L'interface de connexion est login.html sous static
(2) Formulez le chemin URL pour la connexion par formulaire

Lors de l'accès, vous verrez l'interface suivante :

Insérer la description de l'image ici

2.2.3 Résolution du problème 403

Entrez votre compte et votre mot de passe, cliquez sur Connexion et signalez une erreur :

Insérer la description de l'image ici

Problème :
Afin d'éviter l'apparition de CSRF (Cross-site request falsification), la sécurité Spring restreint la plupart des méthodes à l'exception de get.

Insérer la description de l'image ici

Solution :
Contrôle CSRF du bouclier, c'est-à-dire que la sécurité du ressort ne restreint plus le CSRF.
ConfigureWebSecurityConfig

@Override
protected void configure(HttpSecurity http) throws Exception {
    
    
  //屏蔽CSRF控制,即spring security不再限制CSRF      
  http.csrf().disable() 
...
}
2.2.4 Modifier le nom du paramètre de connexion

Les noms par défaut des paramètres de compte et de mot de passe sont : nom d'utilisateur, mot de passe, qui doivent correspondre à l'arrière-plan avant que la connexion normale puisse être effectuée. Bien entendu, Spring Security offre également la possibilité de modifier les noms des paramètres.

Configuration:

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

Méthode de test : modifiez le nom du paramètre dans l'interface et voyez si vous pouvez vous connecter plus tard. Si vous ne parvenez pas à vous connecter, ajoutez la configuration et redémarrez pour vous connecter. Si la connexion réussit, vérifiez que la configuration prend effet.

2.2.5 Configuration de la déconnexion

La sécurité Spring implémente la sortie de déconnexion et l'accès/déconnexion par défaut. Comme prévu, Spring effectue également la fonction de sortie pour nous.

Vous pouvez également personnaliser l'opération de connexion dans Spring Security.
La configuration est la suivante :

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

code du contrôleur

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

interface:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
登出界面
</body>
</html>
2.2.6 Gestionnaire de réussite de connexion personnalisé

La couche inférieure de successForwardUrl qui se connecte avec succès est l'action de transfert de demande, qui ne peut pas être utilisée dans les projets où les front-end et back-end sont séparés.

Code:

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);
    }
}

Configuration:

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

successHandler : lorsque la connexion est réussie, elle sera transmise à notre propre processeur défini pour traitement.

2.2.7 Gestionnaire d'échec de connexion personnalisé

Code:

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);

    }
}

Configuration:

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

FailureHandler : lorsque la connexion échoue, elle est gérée par notre propre processeur défini.

2.3 Autorisation

2.3.1 Autorisation du mode configuration

La mise en œuvre de l'autorisation nécessite l'interception et la vérification de l'accès de l'utilisateur pour vérifier si les autorisations de l'utilisateur peuvent exploiter les ressources spécifiées. Spring Security fournit des méthodes de mise en œuvre de l'autorisation par défaut.

Ajoutez /r/r1 ou /r/r2 à LoginController

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

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

Configurez les règles d'autorisation dans la classe de configuration de sécurité WebSecurityConfifig.java :

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

Explication de la configuration :

  • .antMatchers("/r/r1").hasAuthority("p1") signifie : l'accès à l'URL de la ressource /r/r1 nécessite l'autorisation p1.
  • .antMatchers("/r/r2").hasAuthority("p2") signifie : l'URL qui accède à la ressource /r/r2 doit avoir p2

test:

1. Connectez-vous avec succès

2. Accédez à /r/r1 et /r/r2. Si vous en avez la permission, accédez normalement, sinon renvoyez 403 (Accès refusé)

Remarque : Cette méthode doit être configurée dans SpringSecurityConfig, qui présente certains défauts. S'il existe des centaines d'interfaces en arrière-plan, dont chacune doit être configurée dans cette méthode, cela sera particulièrement déroutant. SpringSecurity propose également une autre méthode. La méthode d'annotation est utilisée plus souvent.Bien sûr, l'utilisation de plus d'annotations ne signifie pas que la méthode d'annotation sera définitivement utilisée dans les projets que nous réalisons.

REMARQUE : L'ordre des règles est important car des règles plus spécifiques doivent être écrites en premier.

Par exemple:

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

L'écriture de /admin/login de cette manière sera également interceptée.

L'ordre devrait être inversé

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

Les méthodes couramment utilisées pour protéger les URL incluent :

Authenticated() protège l'URL et nécessite la connexion de l'utilisateur

permitAll() spécifie que l'URL n'a pas besoin d'être protégée, les applications générales et les fichiers de ressources statiques

hasRole(String role) restreint l'accès à un seul rôle, le rôle sera incrémenté de "ROLE_". Ainsi "ADMIN" sera comparé à "ROLE_ADMIN".

hasAuthority (String Authority) restreint l'accès à une seule autorité

**hasAnyRole(String… rôles)** permet l'accès par plusieurs rôles.

hasAnyAuthority(String… autorités) permet un accès à plusieurs autorités.

access (attribut String) Cette méthode utilise des expressions SpEL, ce qui permet de créer des restrictions complexes.

hasIpAddress(String ipaddressExpression) restreint les adresses IP ou les sous-réseaux

2.3.3 Autorisation d'annotation

Nous maîtrisons maintenant comment utiliser http.authorizeRequests() pour autoriser les ressources Web. À partir de Spring Security version 2.0, il prend en charge la sécurité des méthodes de couche de service. Dans cette section, nous apprenons trois types d'annotations : @PreAuthorize, @PostAuthorize et @Secured.

Nous pouvons activer la sécurité basée sur les annotations à l'aide de l'annotation @EnableGlobalMethodSecurity sur n'importe quelle instance @Configuration.

Ce qui suit activera l'annotation @Secured de Spring Security.

Configuration:

@EnableGlobalMethodSecurity(securedEnabled = true)

Code de réponse:

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

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

Remarque : @Secured est généralement utilisé pour le contrôle d'accès basé sur les rôles.

Ce qui suit activera l'annotation @PreAuthorize de Spring Security.

Configuration:

@EnableGlobalMethodSecurity(prePostEnabled = true)

Code Java correspondant :

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

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

Remarque : @PreAuthorize est généralement basé sur le contrôle d'accès aux autorisations et est utilisé plus souvent.

Je suppose que tu aimes

Origine blog.csdn.net/m0_52896752/article/details/132904967
conseillé
Classement