SpringSecurity5 初体验

回到序章

来来来,点这

实践

引入包

pom.xml

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

Application.java( 启动类 )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;

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

@GetMapping("/test1/{id}")
@ResponseBody
public String test1(@PathVariable String id) {
return "t1-id=" + id;
}

@GetMapping("/test2/{id}")
@ResponseBody
public String test2(@PathVariable String id) {
return "t2-id=" + id;
}
}

启动

默认会提供一个用户名为 user 的账户,密码会在控制台上打印。

SpringSecurity生成的uuid密码

为啥是 user?为啥密码是 uuid ?

通过日志可以看到,这串密码是在 UserDetailsServiceAutoConfiguration 里打印出来的,进入该类找到打印的代码

UserDetailsServiceAutoConfiguration

进入 User 类中,可以看到默认用户是 user,而密码是一个随机的 uuid

User

然后访问项目接口地址,也就是 http://127.0.0.1:8080/index

SpringSecurity默认的登陆页面

输入账号密码,点击 Sign in 即可访问到 /test1/*、/test2/* 接口

附加

每次启动的时候,密码都是随机的 uuid ,要去日志中找不是那么方便,这里提供两个非-常用的方案去设置一个用户提供测试用( 给我测试 / 学习状态下用,正常业务系统别这么搞,被拉去祭天我可不管 = = )

配置文件

因为是 springboot 啊,所以就理所当然的是 application.yml 。

application.yml

1
2
3
4
5
spring:
security:
user:
name: admin
password: admin

完事,可以用 admin:admin 登陆了。但是,这种方式会导致 passwordGenerated 这个值被设置成 false,就会导致控制台不打印 uuid 密码了,所以 user 你没法用了。

相关源码,可以参考点一下配置文件的 password,会进入到 setPassword 方法,这里贴出图

SecurityProperties-setPassword

配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin1").password("{noop}123").roles("admin");
}
}

密码设置的话,涉及到 PasswordEncoder,这里就不详细说了,后面单独出一篇,这里你就只要知道明文的话,写法固定是: {noop}密码

PasswordEncoder 篇

重写 UserDetailService 接口

由于 Spring Security 支持多种数据源,例如内存、数据库、LDAP 等,这些不同来源的数据被共同封装成一个 UserDetailService 接口,任何实现了该接口的对象都可以作为认证数据源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService())
.and()
.inMemoryAuthentication()
.withUser("admin1").password("{noop}123").roles("admin");
}

@Bean
protected UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("admin2").password("{noop}123").roles("admin").build());
return manager;
}
}