前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Boot 安全框架 Spring Security 入门

Spring Boot 安全框架 Spring Security 入门

原创
作者头像
用户8351972
发布2023-02-27 11:34:04
8020
发布2023-02-27 11:34:04
举报
文章被收录于专栏:学习笔记521

1.概述

基本上,在所有的开发的系统中,都必须做认证(authentication)和授权(authorization),以保证系统的安全性。考虑到很多胖友对认证和授权有点分不清楚,在这里引用一个网上有趣的例子

以论坛举例子:

  • 【认证】你要登录论坛,输入用户名张三,密码 1234,密码正确,证明你张三确实是张三,这就是 authentication。
  • 【授权】再一 check 用户张三是个版主,所以有权限加精删别人帖,这就是 authorization 。

所以简单来说:认证解决“你是谁”的问题,授权解决“你能做什么”的问题。

在 Java 生态中,目前有 Spring Security 和 Apache Shiro 两个安全框架,可以完成认证和授权的功能。本文,我们先来学习下 Spring Security 。

2.快速入门

示例代码对应仓库:https://gitee.com/todostyle/tupay-learning.git

代码语言:txt
复制
learn-springsecurity-demo

在本小节中,我们来快速入门下 Spring Security ,实现访问 API 接口时,需要首先进行登录,才能进行访问。

2.1 引入依赖

代码语言:java
复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>tupay-learning</artifactId>
        <groupId>com.tostyle</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>learn-springsecurity-demo</artifactId>

    <dependencies>
        <!-- 实现对 Spring MVC 的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 实现对 Spring Security 的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    </dependencies>

</project>

2.2 增加启动类 SpringSecurityApplication

代码语言:java
复制
package com.tostyle.springsecurity;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author tostyle
 * @date 2023-02-27 10:03
 */
@SpringBootApplication
public class SpringSecurityApplication {

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

2.3 配置文件application.yml

代码语言:java
复制
spring:
  # Spring Security 配置项,对应 SecurityProperties 配置类
  security:
    # 配置默认的 InMemoryUserDetailsManager 的用户账号与密码。
    user:
      name: user # 账号
      password: user # 密码
      roles: ADMIN # 拥有角色
  • 在 spring.security 配置项,设置 Spring Security 的配置,对应 SecurityProperties 配置类。
  • 默认情况下,Spring Boot UserDetailsServiceAutoConfiguration 自动化配置类,会创建一个内存级别的 InMemoryUserDetailsManager Bean 对象,提供认证的用户信息。
代码语言:txt
复制
 这里,我们添加了 spring.security.user 配置项,UserDetailsServiceAutoConfiguration 会基于配置的信息创建一个用户 User 在内存中。
代码语言:txt
复制
 如果,我们未添加 spring.security.user 配置项,UserDetailsServiceAutoConfiguration 会自动创建一个用户名为 "user" ,密码为 UUID 随机的用户 User 在内存中。

2.4 创建HelloController

在 com.tostyle.springsecurity.controller 包路径下,创建 HelloController 类,代码如下:

代码语言:java
复制
package com.tostyle.springsecurity.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author tostyle
 * @date 2023-02-27 10:33
 */
@RestController
@RequestMapping("/hello")
public class HelloController {

    @GetMapping("/demo")
    public String demo() {
        return "Hello SpringSecurity";
    }

}

这里,我们先提供一个 "/hello/demo" 接口,用于测试未登录时,会被拦截到登录界面。

2.5 测试

执行 SpringSecurityApplication#main(String[] args) 方法,运行项目。

项目启动成功后,浏览器访问 http://127.0.0.1:8080/hello/demo 接口。因为未登录,所以被 Spring Security 拦截到登录界面。如下图所示:

image.png
image.png

因为我们没有自定义登录界面,所以默认会使用 DefaultLoginPageGeneratingFilter 类,生成上述界面。

输入我们在「2.3 配置文件」中配置的「user/user」账号,进行登录。登录完成后,因为 Spring Security 会记录被拦截的访问地址,所以浏览器自动动跳转 http://127.0.0.1:8080/admin/demo 接口。访问结果如下图所示:

image.png
image.png

3.进阶使用

代码示例

代码语言:java
复制
learn-springsecurity-demo-role

在「2. 快速入门」中,我们很快速的完成了 Spring Security 的入门。本小节,我们将会自定义 Spring Security 的配置,实现权限控制。

考虑到不污染上述的示例,我们新建一个 learn-springsecurity-demo-role 项目。

3.1 引入依赖

和 「2.1 引入依赖」 一致,见 pom.xml 文件。

3.2 示例一

在示例一中,我们会看看如何自定义 Spring Security 的配置,实现权限控制。

3.2.1 SecurityConfig

在 com.tostyle.springsecurity.config 包下,创建 SecurityConfig 配置类,继承 WebSecurityConfigurerAdapter 抽象类,实现 Spring Security 在 Web 场景下的自定义配置。代码如下:

代码语言:java
复制
package com.tostyle.springsecurity.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * @author tostyle
 * @date 2023-02-27 10:58
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    }
}
  • 我们可以通过重写 WebSecurityConfigurerAdapter 的方法,实现自定义的 Spring Security 的配置。

首先,我们重写 #configure(AuthenticationManagerBuilder auth) 方法,实现 AuthenticationManager 认证管理器。代码如下:

代码语言:java
复制
// SecurityConfig.java
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.
            // <X> 使用内存中的 InMemoryUserDetailsManager
            inMemoryAuthentication()
            // <Y> 不使用 PasswordEncoder 密码编码器
            .passwordEncoder(NoOpPasswordEncoder.getInstance())
            // <Z> 配置 admin 用户
            .withUser("admin").password("admin").roles("ADMIN")
            // <Z> 配置 normal 用户
            .and().withUser("normal").password("normal").roles("NORMAL");
}
  • <X> 处,调用 AuthenticationManagerBuilder#inMemoryAuthentication() 方法,使用内存级别的 InMemoryUserDetailsManager Bean 对象,提供认证的用户信息。
代码语言:txt
复制
* Spring 内置了两种 UserDetailsManager 实现:
代码语言:txt
复制
    *   InMemoryUserDetailsManager,和「2. 快速入门」是一样的。
代码语言:txt
复制
    *   JdbcUserDetailsManager ,基于 JDBC的 JdbcUserDetailsManager 。
代码语言:txt
复制
*  实际项目中,我们更多采用调用 AuthenticationManagerBuilder#userDetailsService(userDetailsService) 方法,使用自定义实现的 UserDetailsService 实现类,更加灵活且自由的实现认证的用户信息的读取。
  • <Y> 处,调用 AbstractDaoAuthenticationConfigurer#passwordEncoder(passwordEncoder) 方法,设置 PasswordEncoder 密码编码器。
代码语言:txt
复制
*  在这里,为了方便,我们使用 NoOpPasswordEncoder 。实际上,等于不使用 PasswordEncoder ,不配置的话会报错。
代码语言:txt
复制
* 生产环境下,推荐使用 BCryptPasswordEncoder 。更多关于 PasswordEncoder 的内容,推荐阅读《该如何设计你的 PasswordEncoder?》文章。
  • <Z> 处,配置了「admin/admin」和「normal/normal」两个用户,分别对应 ADMIN 和 NORMAL 角色。相比「2. 快速入门」来说,可以配置更多的用户。

然后,我们重写 #configure(HttpSecurity http) 方法,主要配置 URL 的权限控制。代码如下:

代码语言:java
复制
// SecurityConfig.java

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            // <X> 配置请求地址的权限
            .authorizeRequests()
                .antMatchers("/test/echo").permitAll() // 所有用户可访问
                .antMatchers("/test/admin").hasRole("ADMIN") // 需要 ADMIN 角色
                .antMatchers("/test/normal").access("hasRole('ROLE_NORMAL')") // 需要 NORMAL 角色。
                // 任何请求,访问的用户都需要经过认证
                .anyRequest().authenticated()
            .and()
            // <Y> 设置 Form 表单登录
            .formLogin()
//                    .loginPage("/login") // 登录 URL 地址
                .permitAll() // 所有用户可访问
            .and()
            // 配置退出相关
            .logout()
//                    .logoutUrl("/logout") // 退出 URL 地址
                .permitAll(); // 所有用户可访问
}
  • <X> 处,调用 HttpSecurity#authorizeRequests() 方法,开始配置 URL 的权限控制。注意看艿艿配置的四个权限控制的配置。下面,是配置权限控制会使用到的方法:
代码语言:txt
复制
*   #(String... antPatterns) 方法,配置匹配的 URL 地址,基于 Ant 风格路径表达式 ,可传入多个。
* 【常用】#permitAll() 方法,所有用户可访问。
* 【常用】#denyAll() 方法,所有用户不可访问。
* 【常用】#authenticated() 方法,登录用户可访问。
*   #anonymous() 方法,无需登录,即匿名用户可访问。
*   #rememberMe() 方法,通过 remember me 登录的用户可访问。
*   #fullyAuthenticated() 方法,非 remember me 登录的用户可访问。
*   #hasIpAddress(String ipaddressExpression) 方法,来自指定 IP 表达式的用户可访问。
* 【常用】#hasRole(String role) 方法, 拥有指定角色的用户可访问。
* 【常用】#hasAnyRole(String... roles) 方法,拥有指定任一角色的用户可访问。
* 【常用】#hasAuthority(String authority) 方法,拥有指定权限(authority)的用户可访问。
* 【常用】#hasAuthority(String... authorities) 方法,拥有指定任一权限(authority)的用户可访问。
* 【最牛】#access(String attribute) 方法,当 Spring EL 表达式的执行结果为 true 时,可以访问。
  • <Y> 处,调用 HttpSecurity#formLogin() 方法,设置 Form 表单登录。
代码语言:txt
复制
*  如果想要自定义登录页面,可以通过 #loginPage(String loginPage) 方法,来进行设置。不过这里我们希望像「2. 快速入门」一样,使用默认的登录界面,所以不进行设置。
  • <Z> 处,调用 HttpSecurity#logout() 方法,配置退出相关。
代码语言:txt
复制
*  如果想要自定义退出页面,可以通过 #logoutUrl(String logoutUrl) 方法,来进行设置。不过这里我们希望像「2. 快速入门」一样,使用默认的退出界面,所以不进行设置。

3.2.2 TestController

在com.tostyle.springsecurity.controller包路径下,创建 TestController 类,提供测试 API 接口。代码如下:

代码语言:java
复制
@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("/echo")
    public String demo() {
        return "示例返回";
    }

    @GetMapping("/home")
    public String home() {
        return "我是首页";
    }

    @GetMapping("/admin")
    public String admin() {
        return "我是管理员";
    }

    @GetMapping("/normal")
    public String normal() {
        return "我是普通用户";
    }

}
  • 对于 /test/echo 接口,直接访问,无需登录。
  • 对于 /test/home 接口,无法直接访问,需要进行登录。
  • 对于 /test/admin 接口,需要登录「admin/admin」用户,因为需要 ADMIN 角色。
  • 对于 /test/normal 接口,需要登录「normal/normal」用户,因为需要 NORMAL 角色。

3.3 示例二

在示例二中,我们会看看如何使用 Spring Security 的注解,实现权限控制。

3.3.1 SecurityConfig

修改 SecurityConfig 配置类,增加 @EnableGlobalMethodSecurity 注解,开启对 Spring Security 注解的方法,进行权限验证。代码如下:

代码语言:java
复制
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter

3.3.2 HelloController

在com.tostyle.springsecurity.controller包路径下,创建 HelloController 类,提供测试 API 接口。代码如下:

代码语言:java
复制
@RestController
@RequestMapping("/hello")
public class DemoController {

    @PermitAll
    @GetMapping("/echo")
    public String demo() {
        return "示例返回";
    }

    @GetMapping("/home")
    public String home() {
        return "我是首页";
    }

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @GetMapping("/admin")
    public String admin() {
        return "我是管理员";
    }

    @PreAuthorize("hasRole('ROLE_NORMAL')")
    @GetMapping("/normal")
    public String normal() {
        return "我是普通用户";
    }

}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.概述
  • 2.快速入门
    • 2.1 引入依赖
      • 2.2 增加启动类 SpringSecurityApplication
        • 2.3 配置文件application.yml
          • 2.4 创建HelloController
            • 2.5 测试
            • 3.进阶使用
              • 3.1 引入依赖
                • 3.2 示例一
                  • 3.2.1 SecurityConfig
                  • 3.2.2 TestController
                • 3.3 示例二
                  • 3.3.1 SecurityConfig
                  • 3.3.2 HelloController
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档