使用 spring-boot,依赖添加 starter-web 和 starter-security。
默认配置
对于一个没有任何额外配置的 controller,默认会使用 spring security 进行保护:
项目启动时会在控制台给出一个随机密码:
Using generated security password: 2fb8492d-410e-4333-998f-5fa5f68ed52f
使用用户名 user
和密码 2fb8492d-410e-4333-998f-5fa5f68ed52f
即可进行登录。
相关源码:
UserDetailsServiceAutoConfiguration
类:
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;
}
SecurityProperties
类中的 User
静态内部类:
/**
* Password for the default user name.
*/
private String password = UUID.randomUUID().toString()
public void setPassword(String password) {
if (!StringUtils.hasLength(password)) {
return;
}
this.passwordGenerated = false;
this.password = password;
}
如果 isPasswordGenerated()
返回 true,则用户没有配置密码,使用 UUID 生成密码。
设置密码
通过配置文件配置
在 spring 配置文件添加如下:
spring.security.user.name=bolitao
spring.security.user.password=bolitao
通过配置类配置
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("bolitao")
.password("bolitao")
.roles("USER", "ADMIN")
.and()
.withUser("testuser")
.password("test")
.roles("USER");
}
}
以上代码以内存方式配置了两个用户:bolitao
和 testuser
,并配置了他们的角色和密码。PasswordEncoder 暂时不管,后面会换成 bcrypt。
配置优先级:代码中的配置 > properties 中的配置
表单认证
做一个简陋的登录表单:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<img src="image/test.png" width="10%" alt="img">
<form action="/login" method="post">
<div class="input">
<label for="username">用户名</label>
<input type="text" name="username" id="username">
<span class="spin"></span>
</div>
<div class="input">
<label for="password">密码</label>
<input type="password" name="passwd" id="password">
<span class="spin"></span>
</div>
<div class="button login">
<button type="submit">
<span>登录</span>
<i class="fa fa-check"></i>
</button>
</div>
</form>
</body>
</html>
在 Spring Security 配置类添加:
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/image/**", "/css/**", "/js/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/login")
.usernameParameter("username")
.passwordParameter("passwd")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout", "POST"))
.and()
.csrf().disable();
}
第一个 configure:对所有 URL 允许特定三个文件夹下的内容。
第二个 configure:
- 所有请求都需要认证
- 指定 form 方式登录,页面地址(GET)为
login.html
,login API 地址(POST)为/login
;自定义表单 username 和 password 名为username
和passwd
(一般不需要改,默认的语义更好);最后放行这两个地址 - 设定注销 URL 为
/logout
(POST 方式) - 暂关闭 CSRF
之后就可以使用自定义的页面,通过表单登录进行 Spring Security 认证了。