前言
之前我写过一些spring security的教程,从原理到实战都涉及一些。由于各种各样的原因拖更几个月,这拖更越久吧也就越不想写了。这次我想换种方式,就写实战的部分,能够更直接的帮助大家。这一来写原理的话我的文字功底不太深厚,写了又删,删了又写,太耗时间。这二来只写实战的话我轻松,大家也能够很直接的看到需要的东西。不多说,开始写代码。
教程目的
本教程使用spring security搭建一个简单的认证授权和访问控制框架,让大家都能够开始使用spring security。
项目准备
- 新建一个spring boot项目
基本操作,spring boot的版本为2.1.7.RELEASE
,这里只给出maven项目pom依赖的内容。注意项目新建完成之后刷新一下pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
- 写一个rest接口(作为我们框架保护的内容)
@RestController
public class DemoController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
}
开始
认识spring security
经过上面的准备工作,我们的项目基本就构建好了。现在开始运行项目。
我这里完整的把console的内容贴出来了。大家可以看到里面有一串随机生成的密码。
项目跑起来之后我们可以在浏览器里面访问一下我们刚才写的接口了。
访问localhost:8080/hello
之后,页面自动跳转到localhost:8080/login
。需要输入用户名和密码,用户名为user
,密码是刚才在控制台打印出来的那一串随机的字符。这里需要说明一下就是,用户名为user是spring security默认的,每次项目重新启动都会重置密码。
输入密码点击Sign in
,我们就会回到localhost:8080/hello
并显示接口返回的内容。
演示完了浏览器访问之后,我们再试试通过postman访问。
postman访问返回的是401状态码,显示未认证无法访问接口。spring boot对浏览器请求和接口请求做了区分返回,spring security也适配了这种情况。
到这里我们最基本的认证授权和访问控制框架就搭建起来了,我们并未对spring security做任何配置。
稍微深入一点
接下来我们要让spring security能够应用在我们真实的项目之中,我们需要spring security使用我们项目中的用户体系,而不是随机密码
要达到这个目的需要了解三个接口。UserDetailsService
、UserDetails
和PasswordEncoder
。UserDetailsService
封装的是通过用户名查询用户的逻辑,UserDetails
封装的是获取用户信息的逻辑,而PasswordEncoder
封装的是密码加密和匹配的逻辑。
我们首先需要实现一个UserDetails
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
public class User implements UserDetails {
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
//下面这个工具类是spring security提供的,逗号隔开的权限字符串转换为AuthorityList
//让每个用户都具有admin和common的权限
return AuthorityUtils.commaSeparatedStringToAuthorityList("admin,common");
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.username;
}
@Override
public boolean isAccountNonExpired() {
//返回true代表账号没有过期
return true;
}
@Override
public boolean isAccountNonLocked() {
//返回true代表账号没有锁定
return true;
}
@Override
public boolean isCredentialsNonExpired() {
//返回true代表账号的密码没有过期
return true;
}
@Override
public boolean isEnabled() {
//返回true代表账号可用
return true;
}
}
该接口里面包含了7个方法,必要的都写了注释,如果看不太明白的话就先跟着做,后面知识储备够了之后自然就明白了,也可以自己去看一下源码,很简单。
接下来我们需要实现一个UserDetailsService
(顺带解决一下PasswordEncoder
)
@Component
public class UserDetailServiceImpl implements UserDetailsService {
@Bean
public PasswordEncoder passwordEncoder() {
//注入PasswordEncoder
return new BCryptPasswordEncoder();
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//在这个方法内实现根据用户名查询用户的业务逻辑
//注意密码需要用PasswordEncoder加密
User user = new User(username, passwordEncoder().encode("123456"));
System.out.println(String.format("用户%s正在尝试登录,数据库密码为123456", username));
return user;
}
}
好了,到这里我们可以再次在浏览器里面尝试一下访问localhost:8080/hello
了,别忘记重启项目哦。
根据我们刚才写的根据用户名查询用户的逻辑,我们的用户名是没有限制的,任意输入。但是密码必须要是123456
,否则就和我们返回的UserDetails匹配不了,登录不上。
我们随便输入一个错误的密码324414,点击登录之后是这样
控制台
输入正确的密码之后登录
结语
完成了。