快速开始
快速开始
在 Spring Boot 项目中引入 Spring Security 同样是简单的引入 starter 封装:
// gradle
compile("org.springframework.boot:spring-boot-starter-security")
// maven
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
...
</dependencies>
然后声明 Web Security 相关的配置:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
...
}
...
}
UserInfo & UserInfoService
UserInfo 对应数据库表中的基本用户信息,如下:
public class UserInfo {
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 角色列表
*/
private List<String> roles;
//Getter & Settter
}
UserInfoService 模拟数据库查询,这里做了简化。
@Service
public class UserInfoService {
/**
* 查询用户信息
* 1. 移除数据库交互,简单实现。
* @param username 用户名称
* @return 结果
*/
public UserInfo queryUserInfo(final String username) {
UserInfo userInfo = new UserInfo();
if("user".equals(username) || "admin".equals(username)) {
userInfo.setUsername(username);
// 密码可以在入库的时候就进行加密
userInfo.setPassword("123456");
// 角色需要以 ROLE_ 开头
userInfo.setRoles(Arrays.asList("ROLE_" + username));
return userInfo;
}
throw new UsernameNotFoundException(username+"对应信息不存在");
}
}
ROLE_
这个前缀主要是为了后面使用角色注解授权的时候需要,默认的前缀就是这个。
WebSecurityConfig 核心配置类
@EnableWebSecurity 启用 web 安全,@EnableGlobalMethodSecurity(prePostEnabled = true) 启用方法级别的安全校验。
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法级安全验证
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService myUserDetailsService;
@Autowired
private MyPasswordEncoder myPasswordEncoder;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService)
.passwordEncoder(myPasswordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated() // 所有请求都需要验证
.and()
.formLogin().permitAll() // 使用默认的登录页面,登录页面允许所有用户访问
.and()
.csrf().disable();// post请求要关闭csrf验证,不然访问报错;实际开发中开启,需要前端配合传递其他参数
}
}
一般情况下,MyUserDetailsService 和 MyPasswordEncoder 这两个类都是需要我们自定义的。
MyUserDetailsService 用户信息查询
我们只需要实现 UserDetailsService 接口,就可以实现对应的查询实现。这里的授权信息,直接使用 SimpleGrantedAuthority 类。
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserInfoService userInfoService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo userInfo = userInfoService.queryUserInfo(username);
// 授权信息构建
List<GrantedAuthority> authorities = new ArrayList<>();
for (String role : userInfo.getRoles()) {
authorities.add(new SimpleGrantedAuthority(role));
}
return new User(
userInfo.getUsername(),
userInfo.getPassword(),
authorities
);
}
}
MyPasswordEncoder 密码加密策略
Spring Security 有很多内置的加密策略,这里为了演示,我自定义了最简单的 plainText 的策略,就是不做任何加密:
@Service
public class MyPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return (String) rawPassword;
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return rawPassword.equals(encodedPassword);
}
}
AuthController 控制器
@RestController
public class AuthController {
/**
* 查看登录用户信息
*/
@GetMapping("/auth")
public Authentication auth(){
return SecurityContextHolder.getContext().getAuthentication();
}
/**
* 只能 user 角色才能访问该方法
* @return 结果
*/
@PreAuthorize("hasAnyRole('user')")
@GetMapping("/user")
public String user(){
return "user角色访问";
}
/**
* 只能 admin 角色才能访问该方法
* @return 结果
*/
@PreAuthorize("hasAnyRole('admin')")
@GetMapping("/admin")
public String admin(){
return "admin角色访问";
}
}
这里我们定义了 3 个方法,第一个方法是获取当前用户的登录信息。后面两个方法都是通过 @PreAuthorize 指定访问需要的角色信息。