spring-security-結合JWT的簡單demo
阿新 • • 發佈:2020-10-16
[github原始碼地址](https://github.com/ghdefe/spring-security-demo)
# spring-security-demo
*前言:本來是想盡量簡單簡單點的寫一個demo的,但是spring-security實在是內容有點多,寫著寫著看起來就沒那麼簡單了,想入門spring-security的話還是需要下些功夫的,這遠沒有Mybatis、JPA之類的容易入門*
一個spring-security採用jwt認證機制的demo。
以下程式碼僅為說明程式碼作用,有的並不完整,如若要參考請git clone整個專案程式碼檢視
參考:
[spring security學習(SpringBoot2.1.5版本)](https://gitee.com/blueses/spring-boot-security)
[SpringBootSecurity學習(13)前後端分離版之JWT](https://www.jianshu.com/p/4eda6471ae51)
[重拾後端之Spring Boot(四):使用JWT和Spring Security保護REST API](https://www.jianshu.com/p/6307c89fe3fa)
## spring-security
config.securityConfig是springSecurity的安全配置類,在這個類中配置需要驗證的介面、需要放行的介面,配置登入成功失敗的處理器
### 1.最簡單的使用者角色許可權控制demo
最簡單是demo是直接在securityConfig中配置存在記憶體中的使用者物件,可以採用一下程式碼配置使用者角色:
```java
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("user").password({noop}123).roles("USER")
.and()
.withUser("admin").password({noop}123).roles("ADMIN")
.and()
.withUser("one").password({noop}123).roles("ONE")
.and()
.withUser("two").password({noop}123).roles("TWO");
}
```
然後在securityConfig加註解開啟介面的preAuth註解支援
```java
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true,jsr250Enabled = true)
public class securityConfig extends WebSecurityConfigurerAdapter {
```
然後可以直接在Controller的介面上加註解
```java
/* 只有角色ONE才能訪問 */
@PreAuthorize("hasRole('ONE')")
@GetMapping("/hello")
public String hello(){
return "hello Spring Security";
}
```
然後訪問localhost:8080/two,發現會跳轉到login登入頁面,此時以one登入進去可以正常訪問,但是以其它角色訪問均會出錯。至此,最簡單的demo已完成。
### 2.修改使用者為資料庫使用者
上面的使用者是存在記憶體中的,接下來需要將其改為從資料庫中獲取使用者資訊並驗證。
首先需要在securityConfig中配置spring-security載入使用者時使用的類,spring-security通過我們提供的這個類得到一個使用者資訊,該使用者資訊中一般包含使用者名稱、密碼、角色,spring-security得到這些資訊後完成後續操作。
提供該類給securityConfig
```
@Qualifier("userDetailServiceImpl")
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService) // 提供給spring-security的類
.passwordEncoder( new BCryptPasswordEncoder() ); // 這是密碼加密的類,可以理解為將明文密碼加密成hash值,可以先忽略照寫
}
```
然後需要實現這個類
```java
@Component
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Autowired
private UserPasswordRepository userPasswordRepository;
@Autowired
private UserRoleRepository userRoleRepository;
/**
* 我的資料庫表分為User表、UserInfo使用者詳細資訊表、UserPassword密碼錶、UserRole使用者角色表
* spring-security會給這個方法提供一個使用者名稱,然後我們實現根據使用者名稱得到這個使用者的UserDetail資訊(類似於包含使用者名稱、密碼、角色的實體類,下一步重寫它)
* 然後返回的就是這個UserDetail,spring-security可以使用該類完成其它的操作
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findFirstByUsername(username);
Integer id = user.getId();
if (Objects.nonNull(user) && username.trim().length() <= 0) {
throw new UsernameNotFoundException("使用者名稱錯誤");
}
// 填充所有角色資訊