spring boot security自定義認(rèn)證的代碼示例
前言
前置閱讀
SpringBoot+Vue前后端分離,使用SpringSecurity完美處理權(quán)限問題的解決方法
說明
實(shí)際場(chǎng)景,我們一般是把用戶信息保存在db中(也可能是調(diào)用三方接口),需要自定義用戶信息加載或認(rèn)證部分的邏輯,下面提供一個(gè)示例。
代碼示例
定義用戶bean
@AllArgsConstructor @Data public class User { private String username; private String password; }
定義Mapper
示例,代碼寫死了,并不是實(shí)際從數(shù)據(jù)庫(kù)或某個(gè)存儲(chǔ)查詢用戶信息:
@Component public class UserMapper { public User select(String username) { return new User(username, "pass"); } }
定義加載用戶數(shù)據(jù)的類
UserDetailsService 是spring security內(nèi)置的加載用戶信息的接口,我們只需要實(shí)現(xiàn)這個(gè)接口:
@Slf4j @Component public class UserDetailsServiceImpl implements UserDetailsService { public static final UserDetails INVALID_USER = new org.springframework.security.core.userdetails.User("invalid_user", "invalid_password", Collections.emptyList()); private final UserMapper userMapper; public UserDetailsServiceImpl(UserMapper userMapper) { this.userMapper = userMapper; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 根據(jù)用戶名從數(shù)據(jù)庫(kù)查詢用戶信息 User user = userMapper.select(username); if (user == null) { /** * 如果沒查詢到這個(gè)用戶,考慮兩種選擇: * 1. 返回一個(gè)標(biāo)記無效用戶的常量對(duì)象 * 2. 返回一個(gè)不可能認(rèn)證通過的用戶 */ return INVALID_USER; // return new User(username, System.currentTimeMillis() + UUID.randomUUID().toString(), Collections.emptyList()); } /** * 這里返回的用戶密碼是否為庫(kù)里保存的密碼,是明文/密文,取決于認(rèn)證時(shí)密碼比對(duì)部分的實(shí)現(xiàn),每個(gè)人的場(chǎng)景不一樣, * 因?yàn)槭褂玫氖遣患用艿腜asswordEncoder,所以可以返回明文 */ return new org.springframework.security.core.userdetails.User(username, user.getPassword(), Collections.emptyList()); } }
自定義認(rèn)證的bean配置
@Configuration public class WebConfiguration { @Bean public PasswordEncoder passwordEncoder() { // 示例,不對(duì)密碼進(jìn)行加密處理 return NoOpPasswordEncoder.getInstance(); } @Bean public AuthenticationManager authenticationManager(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); // 設(shè)置加載用戶信息的類 provider.setUserDetailsService(userDetailsService); // 比較用戶密碼的時(shí)候,密碼加密方式 provider.setPasswordEncoder(passwordEncoder); return new ProviderManager(Arrays.asList(provider)); } }
注意,因?yàn)檫@個(gè)是示例,AuthenticationProvider使用的是spring security的DaoAuthenticationProvider ,在實(shí)際場(chǎng)景中,如果不滿足可以自定義實(shí)現(xiàn)或者繼承DaoAuthenticationProvider ,重寫其中的:additionalAuthenticationChecks方法,主要就是認(rèn)證檢查的,默認(rèn)實(shí)現(xiàn)如下:
@Override @SuppressWarnings("deprecation") protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { if (authentication.getCredentials() == null) { this.logger.debug("Failed to authenticate since no credentials provided"); throw new BadCredentialsException(this.messages .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } String presentedPassword = authentication.getCredentials().toString(); // 就是比對(duì)下請(qǐng)求傳過來的密碼和根據(jù)該用戶查詢的密碼是否一致,passwordEncoder是根據(jù)不同的加密算法進(jìn)行加密,示例我們用的是NoOpPasswordEncoder,也就是原始明文比對(duì) if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { this.logger.debug("Failed to authenticate since password does not match stored value"); throw new BadCredentialsException(this.messages .getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); } }
定義登錄接口
@RequestMapping("/login") @RestController public class LoginController { private final AuthenticationManager authenticationManager; public LoginController(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; } @PostMapping() public Object login(@RequestBody User user) { try { // 使用定義的AuthenticationManager進(jìn)行認(rèn)證處理 Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword())); // 認(rèn)證通過,設(shè)置到當(dāng)前上下文,如果當(dāng)前認(rèn)證過程后續(xù)還有處理的邏輯需要的話。這個(gè)示例是沒有必要了 SecurityContextHolder.getContext().setAuthentication(authenticate); return "login success"; }catch (Exception e) { return "login failed"; } } /** * 獲取驗(yàn)證碼,需要的話,可以提供一個(gè)驗(yàn)證碼獲取的接口,在上面的login里把驗(yàn)證碼傳進(jìn)來進(jìn)行比對(duì) */ @GetMapping("/captcha") public Object captcha() { return "1234"; } }
自定義HttpSecurity
@Component public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // 在這里自定義配置 http.authorizeRequests() // 登錄相關(guān)接口都允許訪問 .antMatchers("/login/**").permitAll() .anyRequest() .authenticated() .and() .exceptionHandling() // 認(rèn)證失敗返回401狀態(tài)碼,前端頁面可以根據(jù)401狀態(tài)碼跳轉(zhuǎn)到登錄頁面 .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase())) .and().cors() // csrf是否決定禁用,請(qǐng)自行考量 .and().csrf().disable() // 采用http 的基本認(rèn)證. .httpBasic(); } }
測(cè)試
示例中,用戶密碼寫死是:pass,用一個(gè)錯(cuò)誤的密碼試一下,響應(yīng)登錄失?。?/p>
使用正確的密碼,響應(yīng)登錄成功:
到此這篇關(guān)于spring boot security自定義認(rèn)證的文章就介紹到這了,更多相關(guān)spring boot security自定義認(rèn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatisPlus3如何向數(shù)據(jù)庫(kù)中存入List
本文主要介紹了Mybatis Plus的類型處理器的使用,通過User.java和UserMapper.xml示例進(jìn)行詳細(xì)的解析,并提供了JSON解析器的使用方法,希望通過這篇文章,可以幫助大家更好的理解和掌握Mybatis Plus的類型處理器2024-10-10詳解Java實(shí)現(xiàn)多種方式的http數(shù)據(jù)抓取
本篇文章主要介紹了Java實(shí)現(xiàn)多種方式的http數(shù)據(jù)抓取,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧。2016-12-12AndroidStudio無法新建Java工程的簡(jiǎn)單解決辦法
AS創(chuàng)建java工程是非常麻煩的,AS沒有提供直接創(chuàng)建java工程的方法且常常無法新建,這篇文章主要給大家介紹了關(guān)于AndroidStudio無法新建Java工程的簡(jiǎn)單解決辦法,需要的朋友可以參考下2024-06-06springboot自動(dòng)配置沒有生效的問題定位(條件斷點(diǎn))
這篇文章主要介紹了springboot自動(dòng)配置未生效問題定位,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面我們來學(xué)習(xí)一下吧2019-06-06Spring AOP實(shí)現(xiàn)功能權(quán)限校驗(yàn)功能的示例代碼
本篇文章主要介紹了Spring AOP實(shí)現(xiàn)功能權(quán)限校驗(yàn)功能的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-12-12MyBatis使用注解開發(fā)實(shí)現(xiàn)過程詳解
這篇文章主要介紹了MyBatis使用注解開發(fā)實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03