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的快捷方式。