您好,我是湘王,這是我的博客園,歡迎您來,歡迎您再來~
前面運行寫好的代碼之所以沒有任何顯示,是因為還沒有對Spring Security進行配置,當然啥也不顯示了,這就好比你坐在車上,卻不打開發動機,車子當然跑不起來,所以咱們就來讓它跑起來,不過在配置之前,有必要對Spring Security的登錄流程做個大致了解,
如果深入原始碼去了解,這個玩意及其復雜,但是沒必要,知道它的機制就行了,就好比你買車也不必把發動機拆開去看它是怎么作業的吧,簡單來說它就是下面這些步驟:
1、Spring Security通過AuthenticationManager介面進行身份驗證
2、ProviderManager是AuthenticationManager的一個默認實作
3、ProviderManager把驗證作業委托給了AuthenticationProvider介面
4、AuthenticationProvider的實作類DaoAuthenticationProvider會檢查身份認證
5、DaoAuthenticationProvider又把認證作業委托給了UserDetailsService介面
6、自定義UserDetailsService類從資料庫中獲取用戶賬號、密碼、角色等資訊,然后封裝成UserDetails回傳
7、使用Spring Security還需要自定義AuthenticationProvider介面,獲取用戶輸入的賬號、密碼等資訊,并封裝成Authentication介面
8、將UserDetails和Authentication進行比對,如果一致就回傳UsernamePasswordAuthenticationToken,否則拋出例外
下面是認證流程圖:

首先重寫loadUserByUsername:
/**
* 自定義用戶詳情
*
* @author 湘王
*/
@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private UserRoleService userRoleService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Collection<GrantedAuthority> authorities = new ArrayList<>();
// 從資料庫中取出用戶資訊
SysUser user = userService.getByName(username);
// 判斷用戶是否存在
if(null == user) {
System.out.println("user is not exist");
throw new UsernameNotFoundException("user is not exist");
}
// 獲得用戶角色:方式一
List<SysUserRole> list = userRoleService.getByUserId(user.getId());
// // 獲得用戶角色:方式二
// List<SysRole> list = roleService.getByUserId(user.getId());
// // 給用戶添加授權:方式一
// for (SysUserRole userRole : list) {
// SysRole role = roleService.getById(userRole.getRoleid());
// authorities.add(new SimpleGrantedAuthority(role.getName()));
// }
// // 回傳UserDetails實作類
// return new User(user.getName(), user.getPassword(), authorities);
// 給用戶添加授權:方式二
return User
.withUsername(username)
.password(user.getPassword())
.authorities(list.stream()
.filter(Objects::nonNull)// 判斷是否為空
.map(userRole -> roleService.getById(userRole.getRoleid()))// 從SysUserRole獲取Role
.map(SysRole::getName)// 轉變為角色名稱字串
.map(SimpleGrantedAuthority::new)// 依據角色名稱創建SimpleGrantedAuthority
.toArray(SimpleGrantedAuthority[]::new)// list轉變為陣列
).build();
}
}
因為UserDetailsService回傳了封裝的UserDetails,所以需要再自定義AuthenticationProvider回傳Authentication介面:
/**
* 自定義登錄驗證
*
* @author 湘王
*/
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 獲取表單輸入中回傳的用戶名
String username = (String) authentication.getPrincipal();
// 獲取表單中輸入的密碼
String password = (String) authentication.getCredentials();
// 這里呼叫我們的自己寫的獲取用戶的方法
UserDetails userInfo = customUserDetailsService.loadUserByUsername(username);
if (userInfo == null) {
System.out.println("user is not exist");
throw new UsernameNotFoundException("user is not exist");
}
PasswordEncoder passwordEncoder = new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
};
// 采用簡單密碼驗證
if (!passwordEncoder.matches(password, userInfo.getPassword())) {
System.out.println("user or password error");
throw new BadCredentialsException("user or password error");
}
Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
// 構建回傳的用戶登錄成功的token
return new UsernamePasswordAuthenticationToken(userInfo, password, authorities);
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
接著來實作實作WebSecurityConfigurerAdapter,它通過重寫WebSecurityConfigurerAdapter中的相關方法(一般是configurer)來自定義配置,WebSecurityConfigurerAdapter主要做幾件事:
1、初始化
2、開啟Security
3、配置各種過濾器,實作驗證過濾器鏈
下面是它的代碼:
/**
* spring security驗證配置
*
* @author 湘王
*/
// 配置類
@Configuration
// 開啟Security服務
@EnableWebSecurity
// 開啟全域Securtiy注解
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
private CustomAuthenticationProvider authenticationProvider;
// 自定義的登錄驗證邏輯
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
// 控制邏輯
@Override
protected void configure(HttpSecurity http) throws Exception {
// 執行UsernamePasswordAuthenticationFilter之前添加攔截過濾
http.addFilterBefore(new CustomInterceptorFilter(), UsernamePasswordAuthenticationFilter.class);
http.authorizeRequests()
.anyRequest().authenticated()
// 設定自定義認證成功、失敗及登出處理器
.and().formLogin().loginPage("/login")
.and().cors()
.and().csrf().disable();
}
@Override
public void configure(WebSecurity web) throws Exception {
// 設定攔截忽略檔案夾,可以對靜態資源放行
web.ignoring().antMatchers("/css/**", "/js/**");
}
}
接著用postman進行測驗:

回顧整個呼叫程序,它的時序圖是:

但是等等:好像除了/login,其他方法都不能正常訪問!
感謝您的大駕光臨!咨詢技術、產品、運營和管理相關問題,請關注后留言,歡迎騷擾,不勝榮幸~
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/538115.html
標籤:Java
