Springboot整合SpringSecurity

  • 一、概述
  • 二、快速入门
  • 2.1 引入依赖
  • 2.2 Application
  • 2.3 配置文件
  • 2.4 AdminController
  • 2.5 简单测试
  • 三、进阶使用
  • 3.1 引入依赖
  • 3.2 示例一
  • 3.2.1 SecurityConfig
  • 3.2.2 TestController
  • 3.3 示例二
  • 3.3.1 SecurityConfig2
  • 3.3.2 DemoController
  • 四、整合 JWT
  • 五、项目实践


一、概述

基本上,在所有的开发的系统中,都必须做认证(authentication)和授权(authorization),以保证系统的安全性。

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

二、快速入门

2.1 引入依赖

<!-- 实现对 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>

2.2 Application

创建 Application.java 类,配置 @SpringBootApplication 注解 :

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

2.3 配置文件

application.yml 中,添加 Spring Security 配置 :

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

2.4 AdminController

AdminController 类,提供管理员 API 接口 :

@RestController
@RequestMapping("/admin")
public class AdminController {
    @GetMapping("/demo")
    public String demo() {
        return "示例返回";
    }
}

2.5 简单测试

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

java springboot集成netty springboot集成spring_spring

三、进阶使用

3.1 引入依赖

3.2 示例一

自定义 Spring Security 的配置,实现权限控制。

3.2.1 SecurityConfig
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @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");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // <M> 配置请求地址的权限
                .authorizeRequests()
                // 所有用户可访问
                .antMatchers("/test/echo").permitAll()
                // 需要 ADMIN 角色
                .antMatchers("/test/admin").hasRole("ADMIN")
                // 需要 NORMAL 角色
                .antMatchers("/test/normal").access("hasRole('ROLE_NORMAL')")
                // 任何请求,访问的用户都需要经过认证
                .anyRequest().authenticated()
                .and()
                // <N> 设置 Form 表单登陆
                .formLogin()
                // 登陆 URL 地址 所有用户可访问
                //.loginPage("/login")
            	.permitAll()
                .and()
                // 配置退出相关
                .logout()
                //退出 URL 地址 所有用户可访问
                //.logoutUrl("/logout")
            	.permitAll();
    }
}
  • <x> 处,调用 inMemoryAuthentication() 方法,使用内存级别InMemoryUserDetailsManager Bean 对象,提供认证的用户信息。
  • 实际项目中,更多采用调用 userDetailsService(userDetailsService) 方法,使用自定义实现的 UserDetailsService 实现类,更加灵活自由的实现认证的用户信息的读取。
  • <Y> 处,调用 passwordEncoder(passwordEncoder) 方法,设置 PasswordEncoder 密码编码器。
  • <Z> 处,配置了「admin/admin」和「normal/normal」两个用户,分别对应 ADMIN 和 NORMAL 角色。
  • <M> 处,调用 authorizeRequests() 方法,开始配置 URL 的权限控制
  • #(String... antPatterns) 方法,配置匹配的 URL 地址,基于 Ant 风格路径表达式 ,可传入多个。
  • 【常用】#permitAll() 方法,所有用户可访问。
  • 【常用】#denyAll() 方法,所有用户不可访问。
  • 【常用】#authenticated() 方法,登陆用户可访问。
  • #anonymous() 方法,无需登陆,即匿名用户可访问。
  • #rememberMe() 方法,通过 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 时,可以访问。
  • <N> 处,调用 formLogin() 方法,设置 Form 表单登陆
  • 如果想要自定义登陆页面,可以通过 #loginPage(String loginPage) 方法,来进行设置。
  • 如果想要自定义退出页面,可以通过 #logoutUrl(String logoutUrl) 方法,来进行设置。
3.2.2 TestController
@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 角色。

登陆「normal/normal」用户后,去访问 /test/admin 接口,会返回 403 界面,无权限~

java springboot集成netty springboot集成spring_自定义_02

3.3 示例二

使用 Spring Security 的注解,实现权限控制。

3.3.1 SecurityConfig2

增加 @EnableGlobalMethodSecurity 注解,开启对 SpringSecurity 注解的方法,进行权限验证。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig2 {
}
3.3.2 DemoController
@RestController
@RequestMapping("/demo")
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 "我是普通用户";
    }
}
  • @PermitAll 注解,等价于 #permitAll() 方法,所有用户可访问。
  • 重要!因为在 SecurityConfig中,配置了 .anyRequest().authenticated() ,任何请求,访问的用户都需要经过认证。所以这里 @PermitAll 注解实际是不生效的。也就是说,Java Config 配置的权限,和注解配置的权限,两者是叠加的。
  • @PreAuthorize 注解,等价于 #access(String attribute) 方法,,当 Spring EL 表达式的执行结果为 true 时,可以访问。

四、整合 JWT

五、项目实践

待续…