1.1导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
1.2配置用户信息和权限类
SpringSecurity中存在一个UserDetails接口的实现类org.springframework.security.core.userdetails.User,它有三个参数,分别是用户名、密码和权限集。我们需要通过自定义 UserDetailsService将用户和权限信息注入进去。(也可以直接创建写入,通过自定义UserDetailsService主要是为了从数据库中读取用户信息)。
- 直接配置
@Bean
public UserDetailsService userDetailsService() throws Exception {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build());
return manager;
}
- 从数据库中读取
@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private SysUserService userService;
@Autowired
private SysRoleService roleService;
@Autowired
private SysUserRoleService userRoleService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Collection<GrantedAuthority> authorities = new ArrayList<>();
// 从数据库中取出用户信息
SysUser user = userService.selectByName(username);
// 判断用户是否存在
if(user == null) {
throw new UsernameNotFoundException("用户名不存在");
}
// 添加权限
List<SysUserRole> userRoles = userRoleService.listByUserId(user.getId());
for (SysUserRole userRole : userRoles) {
SysRole role = roleService.selectById(userRole.getRoleId());
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
// 返回UserDetails实现类
return new User(user.getName(), user.getPassword(), authorities);
}
}
1.3自定义WebSecurityConfigurerAdapter的子类进行自定义登录认证配置
Spring Security基于表单的身份验证是WebSecurityConfigurerAdapter在configure(HttpSecurity http)方法中提供了一个默认配置,我们可通过自定义其子类WebSecurityConfig,实现自己的表单验证登录配置。
默认配置
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated() 1
.and()
.formLogin() 2
.and()
.httpBasic(); 3
}
- 确保对我们的应用程序的任何请求都要求用户进行身份验证
- 允许用户使用基于表单的登录进行身份验证
- 允许用户使用HTTP基本身份验证进行身份验证
虽然自动生成的登录页面便于快速启动和运行,但大多数应用程序都希望提供自己的登录页面。为此,我们可以更新我们的配置,如下所示:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login") 1
.permitAll(); 2
}
- 更新的配置指定登录页面的位置。
- 我们必须授予所有用户(即未经身份验证的用户)访问我们的登录页面的权限。formLogin().permitAll()方法允许为与基于表单的登录相关联的所有URL授予对所有用户的访问权限。
我们可以通过向http.authorizeRequests()方法添加多个子项来指定网址的自定义要求。例如:
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests() 1
.antMatchers("/resources/**", "/signup", "/about").permitAll() 2
.antMatchers("/admin/**").hasRole("ADMIN") 3
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") 4
.anyRequest().authenticated() 5
.and()
// ...
.formLogin();
}
- http.authorizeRequests()方法有多个子项,每个匹配器按其声明的顺序进行考虑。
- 我们指定了任何用户都可以访问的多种URL模式。具体来说,如果URL以“/ resources /”开头,等于“/ signup”或等于“/ about”,则任何用户都可以访问请求。
- 任何以“/ admin /”开头的URL都将仅限于具有“ROLE_ADMIN”角色的用户。您会注意到,由于我们正在调用hasRole方法,因此我们不需要指定“ROLE_”前缀。
- 任何以“/ db /”开头的URL都要求用户同时拥有“ROLE_ADMIN”和“ROLE_DBA”。您会注意到,由于我们使用的是hasRole表达式,因此我们不需要指定“ROLE_”前缀。
- 任何尚未匹配的URL只需要对用户进行身份验证
使用WebSecurityConfigurerAdapter时,会自动应用注销功能。默认情况下,访问URL /logout将通过以下方式记录用户:
- 使HTTP会话无效
- 清理已配置的任何RememberMe身份验证
- 清除SecurityContextHolder
- 重定向到/login?logout
但是,与配置登录功能类似,您还可以使用各种选项来进一步自定义注销要求:
protected void configure(HttpSecurity http) throws Exception {
http
.logout() 1
.logoutUrl("/my/logout") 2
.logoutSuccessUrl("/my/index") 3
.logoutSuccessHandler(logoutSuccessHandler) 4
.invalidateHttpSession(true) 5
.addLogoutHandler(logoutHandler) 6
.deleteCookies(cookieNamesToClear) 7
.and()
...
}
- 提供注销支持。使用WebSecurityConfigurerAdapter时会自动应用此选项。
- 触发注销的URL(默认为/logout)。如果启用了CSRF保护(默认),则该请求也必须是POST。
- 注销后重定向到的URL。默认值为/login?logout。
- 我们指定一个自定义LogoutSuccessHandler。如果指定了此项,则忽略logoutSuccessUrl()。
- 指定在注销时是否使HttpSession无效。默认情况下这是真的。
- 添加LogoutHandler。默认情况下,SecurityContextLogoutHandler被添加为最后一个LogoutHandler。
- 允许指定在注销成功时删除的cookie的名称。这是显式添加CookieClearingLogoutHandler的快捷方式。