1. 程式人生 > >spring-security-結合JWT的簡單demo

spring-security-結合JWT的簡單demo

[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("使用者名稱錯誤"); } // 填充所有角色資訊