本文主要介紹怎麼快速搭建一個帶spring security安全認證的應用,其他基礎介紹,基本操作,內容原理略過,着重介紹實現步驟,如需詳細瞭解請閱讀相關文檔。
0.環境
- jdk 1.8
- spring boot
- MySQL 5
需要準備5張表:
以上爲5張表需要的字段,可根據實際需求變更
1.引入spring security
創建一個spring boot工程,在pom.xml里加入spring security的依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.實現表單登錄
不做任何配置的話,spring security採用默認的賬號密碼登錄,賬號user,密碼在項目啓動時會在控制檯打印出來。
按照實際需求我們需要讀取數據庫的用戶進行登錄:
2.1自定義WebSecurityConfigurerAdapter
創建 MySecurityConfig 並且繼承WebSecurityConfigurerAdapter,重寫它的configure(HttpSecurity http)
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()//所有請求需登錄
.and()
.formLogin()
.and()
.logout().logoutUrl("/logout");
}
}
2.2從數據庫讀取用戶數據
創建一個服務實現UserDetailsService裏的loadUserByUsername即可
@Service
public class UserAuthService implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntity userEntity = userService.getByUsername(username);
if (userEntity == null) {
throw new UsernameNotFoundException("用戶不存在!");
}
return new User(userEntity.getUsername(), userEntity.getPassword(), new ArrayList<>());
}
}
userService.getByUsername(username);爲根據用戶名從數據庫中讀取用戶信息,自行實現,這裏不做詳細介紹。
把這個服務加入2.1創建的配置裏:
最後MySecurityConfig配置爲:
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserAuthService userAuthService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()//所有請求需登錄
.and()
.formLogin()
.and()
.logout().logoutUrl("/logout");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userAuthService).passwordEncoder(new BCryptPasswordEncoder());
}
}
spring security需要對密碼進行加密,這裏使用BCryptPasswordEncoder:
String password = new BCryptPasswordEncoder().encode("要加密的密碼");
可以用上面的方式將密碼加密並存入數據庫。
至此,所有配置已完成,啓動項目即可。
2.3自定義登錄頁
啓動項目後,spring security有默認的登錄頁:
如需修改在2.1的配置里加入loginPage即可:
3.自定義授權
spring security的權限認證在2.1的configure里加入antMatchers("路徑").需要權限()來實現,它有個access()方法可以自定義表達式來實現權限驗證,因此我們可以寫個方法來實現自己需要的權限驗證。如圖所示:
以下爲實現步驟:
3.1將權限信息加入用戶數據裏
在2.2的UserAuthService 獲取到用戶信息後,查詢其擁有的權限,並將允許訪問的url加入用戶信息裏,最後UserAuthService 變爲:
@Service
public class UserAuthService implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntity userEntity = userService.getByUsername(username);
if (userEntity == null) {
throw new UsernameNotFoundException("用戶不存在!");
}
//根據用戶ID獲取其擁有的權限,並將其url加入用戶的權限裏
List<SimpleGrantedAuthority> permissionList = userService.getPermissionByUserId(userEntity.getId())
.stream()
.map(PermissionEntity::getUrl)
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
return new User(userEntity.getUsername(), userEntity.getPassword(), permissionList);
}
}
userService.getPermissionByUserId(userEntity.getId())爲根據用戶id從數據庫中連表查詢用戶擁有的權限列表,自行實現,這裏不做詳細介紹。
3.2 自定義URL認證方法
之前說過用.access("@authorizeService.check(authentication,request)")來實現,創建一個authorizeService,編寫一個認證方法check(authentication,request),authentication爲用戶的認證信息,request爲請求,在3.1中我們已經將用戶可以訪問的url放入了authentication,因此只要authentication的權限信息裏包含有request請求的url,那麼就認證通過。
@Service("authorizeService")
public class AuthorizeService {
public boolean check(Authentication authentication, HttpServletRequest request) {
Object principal = authentication.getPrincipal();
//判斷是否是認證的用戶
if (principal != null && principal instanceof UserDetails) {
UserDetails user = (UserDetails) principal;
//獲取認證用戶裏的url列表
Set<SimpleGrantedAuthority> authorities = (Set<SimpleGrantedAuthority>) user.getAuthorities();
//判斷url列表裏是否包含request請求的url
boolean contains = authorities.stream()
.map(SimpleGrantedAuthority::getAuthority)
.anyMatch(request.getRequestURI()::equals);
return contains;
}
return false;
}
}
3.3 配置需要自定義認證的地方
在2.1的configure里加入鏈接.access("@authorizeService.check(authentication,request)")即可,如:
.antMatchers("/admin/**").access("@authorizeService.check(authentication,request)")
.anyRequest().access("@authorizeService.check(authentication,request)")
至此,所有的配置已完成。