上一篇文章我们到了Spring Security 文档的第四大点 Samples and Guides (Start Here)
这一章的话主要是列举了一下让大家快速入门的Security例子。
Table 4.1. Sample Applications
Source | Description | Guide |
---|---|---|
Hello Spring Security |
Demonstrates how to integrate Spring Security with an existing application using Java-based configuration. |
Hello Spring Security Guide |
Hello Spring Security Boot |
Demonstrates how to integrate Spring Security with an existing Spring Boot application. |
Hello Spring Security Boot Guide |
Hello Spring Security XML |
Demonstrates how to integrate Spring Security with an existing application using XML-based configuration. |
Hello Spring Security XML Guide |
Hello Spring MVC Security |
Demonstrates how to integrate Spring Security with an existing Spring MVC application. |
Hello Spring MVC Security Guide |
Custom Login Form |
Demonstrates how to create a custom login form. |
Custom Login Form Guide |
OAuth 2.0 Login |
Demonstrates how to integrate OAuth 2.0 Login with an OAuth 2.0 or OpenID Connect 1.0 Provider. |
OAuth 2.0 Login Guide |
由于现在SpringBoot很火,所以我们选择第二个例子来作为入门事例(有用SpringMVC比较惯的话,可以尝试下第四个
我们从这个Guide进入Hello Spring Security Boot Guide
下载到示例源码后,导入SPRING_SECURITY_HOME/samples/boot/insecure,结果发现是个gradle工程。要先给电脑配置了gradle环境后才可以正常导入。(没用过gradle的可以看下windows下安装gradle)
导入后,等待gradle构建(不得不说,真的是慢,再吐槽下后面的文档是用maven构建来说明的,这里下载却是用gradle)。
==============
由于此时构建方式的不同,我决定还是根据文档自己建一个maven工程吧
==============
发现当加入下面依赖的时候,就会到了一个登陆页面
org.springframework.boot
spring-boot-starter-security
此时我的目录如下:并还没有对security进行配置,只是加了pom依赖而已。这里SpringBoot默认对Security进行了实现。
我们修改一下yml的日志配置改成info级别的,
logging:
level:
root: INFO
org.springframework.web: INFO
再次启动就能够看到有下面的内容显示,根据输出的类名能看得出是一个自动配置
2018-09-05 23:04:43.979 INFO 15096 --- [ main] .s.s.UserDetailsServiceAutoConfiguration :
Using generated security password: 95e0ee07-e079-46a6-9d33-fc94cacc8ae7
访问http://localhost:8080 ,用户名用user,password用上面的内容就能够成功登录
在依赖的sprin-boot-autoconfigure包下面找到org.springframework.boot.autoconfigure.security.servlet包下面找到UserDetailsServiceAutoConfiguration 的源码看一下(怎么找到这个类的可以看下这篇文章)
public InMemoryUserDetailsManager inMemoryUserDetailsManager(
SecurityProperties properties,
ObjectProvider passwordEncoder) {
SecurityProperties.User user = properties.getUser();
List roles = user.getRoles();
return new InMemoryUserDetailsManager(User.withUsername(user.getName())
.password(getOrDeducePassword(user, passwordEncoder.getIfAvailable()))
.roles(StringUtils.toStringArray(roles)).build());
}
private String getOrDeducePassword(SecurityProperties.User user,
PasswordEncoder encoder) {
String password = user.getPassword();
if (user.isPasswordGenerated()) {
logger.info(String.format("%n%nUsing generated security password: %s%n",
user.getPassword()));
}
if (encoder != null || PASSWORD_ALGORITHM_PATTERN.matcher(password).matches()) {
return password;
}
return NOOP_PASSWORD_PREFIX + password;
}
发现user是通过使用SecurityProperties实例的getUser方法获得的。看一下SecurityProperties的源码
private User user = new User();
public User getUser() {
return this.user;
}
而这里在SecurityProperties内部有一个static的User,看到这里才真相大白。
public static class User {
/**
* Default user name.
*/
private String name = "user";
/**
* Password for the default user name.
*/
private String password = UUID.randomUUID().toString();
/**
* Granted roles for the default user name.
*/
private List roles = new ArrayList<>();
private boolean passwordGenerated = true;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
if (!StringUtils.hasLength(password)) {
return;
}
this.passwordGenerated = false;
this.password = password;
}
public List getRoles() {
return this.roles;
}
public void setRoles(List roles) {
this.roles = new ArrayList<>(roles);
}
public boolean isPasswordGenerated() {
return this.passwordGenerated;
}
}
用户名使用的是"user", password使用的是随机的UUID
并且User的Role是一个List,也就表明了一个User的身份角色允许有多个。