Spring Security
是一個(gè)功能強(qiáng)大且高度可定制的身份驗(yàn)證和訪問控制框架, 提供了完善的認(rèn)證機(jī)制和方法級的授權(quán)功能。是一款非常優(yōu)秀的權(quán)限管理框架。它的核心是一組過濾器鏈,不同的功能經(jīng)由不同的過濾器。 今天通過一個(gè)簡單的案例了解一下Spring Security
的基本用法
1.引入依賴
在項(xiàng)目中引入Spring Security
依賴,代碼如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
引入依賴后,整個(gè)項(xiàng)目都被Spring Security
保護(hù)起來,所有的接口都要登錄之后才能訪問了,例如,我需要訪問/doc.html
接口文檔,直接跳到登錄頁面。如下圖:
這時(shí),你會有十萬個(gè)為什么啦?這個(gè)頁面哪里的?這個(gè)用戶名和密碼是啥?等等。不著急,聽我一一道來。
2.用戶名和密碼在哪里設(shè)置
當(dāng)我們引入了Spring Secruity依賴后,啟動(dòng)項(xiàng)目之后,密碼就會在控制臺中輸出的,格式是UUID,每一次啟動(dòng)密碼都不一樣的,而用戶名是默認(rèn)是User的。
Using generated security password: 8b2d752b-8892-4cd3-a7a9-a36e79e1cad8
我們可以通過項(xiàng)目的配置文件自定義用戶名和密碼的,代碼如下,這樣每次重啟項(xiàng)目,用戶名和密碼都是固定不變的。
spring:
security:
user:
name: didiplus
password: didiplus
3.UserDetailsService接口詳解
UserDetailsService
接口只有一個(gè)抽象方法就是loadUserByUsername(String username)
。代碼如下:
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
UserDetailsService
接口的返回值是UserDetails
接口, 這又是一個(gè)接口,Spring Security
框架提供了它的實(shí)現(xiàn)類org.springframework.security.core.userdetails
包下的User類對象 。userdetails
源碼如下:
Spring Security
提供了三個(gè)UserDetailsService
接口的實(shí)現(xiàn)類,分別是CachingUserDetailsService
,JdbcDaoImpl
,InMemoryUserDetailsManager
3.1JdbcDaoImpl實(shí)現(xiàn)類
該實(shí)現(xiàn)類是通過數(shù)據(jù)庫獲取用戶名和密碼,JdbcUserDetailsManager
中定義了一大堆SQL語句,如下:
接著我們在看一下JdbcDaoImpl
中的loadUsersByUsername
方法,如下:
3.2InMemoryUserDetailsManager實(shí)現(xiàn)類
以上代碼是判斷內(nèi)存中的HashMap
集合中是否有用戶數(shù)據(jù)對應(yīng)的User對象,如果沒有,直接拋出異常,如果有就返回該用戶的User對象信息。
以上代碼是把配置文件中的User
相關(guān)信息讀取到。通過分析源碼發(fā)現(xiàn) Spring Security
框架完成用戶登錄認(rèn)證的核心就在與org.springframework.security.core.userdetails
包下的UserDetailsService
接口。
3.3自定義實(shí)現(xiàn)類實(shí)現(xiàn)UserDetailsService接口
自定義實(shí)現(xiàn)類MyUserDetailsServiceImpl,代碼如下:
@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {
private static final String USERNAME="admin";
private static final String PASSWORD="admin123";
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (!USERNAME.equals(username)){
throw new UsernameNotFoundException("用戶名不存在");
}
UserDetails userDetails = new User(USERNAME,PASSWORD, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,common"));
return userDetails;
}
}
重啟項(xiàng)目看看,輸入定義的用戶名和密碼,發(fā)現(xiàn)登錄不了,查看控制臺發(fā)現(xiàn)報(bào)錯(cuò),提示如下:
報(bào)錯(cuò)的原因是沒有使用任何的PasswordEncoder
,我們輸入的密碼沒有用加密工具進(jìn)行加密 。 Spring Security
其實(shí)已經(jīng)給我們提供了很多的PasswordEncoder
。 在org.springframework.security.crypto.password
包下有一個(gè)PasswordEncoder
接口,看看他的實(shí)現(xiàn)類
把這個(gè)PasswordEncoder的任意一個(gè)我們需要用來加密密碼的實(shí)現(xiàn)類的Bean注入到容器里面,就可以直接拿來使用 ,代碼如下:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
修改MyUserDetailsServiceImpl
類如下:
@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {
private static final String USERNAME="admin";
private static final String PASSWORD="admin123";
@Resource
BCryptPasswordEncoder cryptPasswordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (!USERNAME.equals(username)){
throw new UsernameNotFoundException("用戶名不存在");
}
UserDetails userDetails = new User(USERNAME,cryptPasswordEncoder.encode(PASSWORD), AuthorityUtils.commaSeparatedStringToAuthorityList("admin,common"));
return userDetails;
}
}
重啟項(xiàng)目再次測試,輸入定義的賬號和密碼。即可訪問到接口文檔頁面。
4.如何修改登錄頁面
覺得默認(rèn)的登錄頁面很丑,我們?nèi)绾味x自己的登錄頁面呢?方法也很簡單,首先我們先去準(zhǔn)備一個(gè)登錄頁面。如下:
前端代碼如下:
<form action="/login" class="login-form" >
<h1>登錄</h1>
<div class="txtb">
<input type="text" name="user">
<span data-placeholder="Username"></span>
</div>
<div class="txtb">
<input type="password" name="pass">
<span data-placeholder="Password"></span>
</div>
<input type="submit" class="logbtn" value="登錄">
<div class="bottom-text">
Don't have account? <a href="#" rel="external nofollow" >Sign up</a>
</div>
</form>
把登錄頁面文件存放到項(xiàng)目的資源文件夾中static
目錄下,然后在SecurityConfig
重寫configure(HttpSecurity http)
這個(gè)方法,代碼如下:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/login.html") #自定義登錄頁面
.usernameParameter("user") #對應(yīng)前端表達(dá)name屬性
.passwordParameter("pass") #對應(yīng)前端表達(dá)name屬性
.loginProcessingUrl("/login")
.defaultSuccessUrl("/doc.html") #登錄成功后跳轉(zhuǎn)的頁面地址
.failureUrl("/login?error=true")
.and()
.authorizeRequests()
.antMatchers("/login.html").permitAll() #放通登錄頁面
.anyRequest().authenticated(); #其他請求都要認(rèn)證
http.csrf().disable();
}
重新啟動(dòng)項(xiàng)目,輸入定義的用戶名和密碼,登錄成功直接跳轉(zhuǎn)到/doc.html
。
antMatchers("url").permitAll() 是把某個(gè)url放通,不需要登錄就能訪問。
到此這篇關(guān)于一文詳解Spring Security的基本用法的文章就介紹到這了,更多相關(guān)Spring Security用法內(nèi)容請搜索html5模板網(wǎng)以前的文章希望大家以后多多支持html5模板網(wǎng)!