spring boot security自定義認(rèn)證的代碼示例
前言
前置閱讀
SpringBoot+Vue前后端分離,使用SpringSecurity完美處理權(quán)限問(wèn)題的解決方法
說(shuō)明
實(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) {
/**
* 如果沒(méi)查詢到這個(gè)用戶,考慮兩種選擇:
* 1. 返回一個(gè)標(biāo)記無(wú)效用戶的常量對(duì)象
* 2. 返回一個(gè)不可能認(rèn)證通過(guò)的用戶
*/
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)求傳過(guò)來(lái)的密碼和根據(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)證通過(guò),設(shè)置到當(dāng)前上下文,如果當(dāng)前認(rèn)證過(guò)程后續(xù)還有處理的邏輯需要的話。這個(gè)示例是沒(méi)有必要了
SecurityContextHolder.getContext().setAuthentication(authenticate);
return "login success";
}catch (Exception e) {
return "login failed";
}
}
/**
* 獲取驗(yàn)證碼,需要的話,可以提供一個(gè)驗(yàn)證碼獲取的接口,在上面的login里把驗(yàn)證碼傳進(jìn)來(lái)進(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)接口都允許訪問(wèn)
.antMatchers("/login/**").permitAll()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
// 認(rèn)證失敗返回401狀態(tài)碼,前端頁(yè)面可以根據(jù)401狀態(tài)碼跳轉(zhuǎn)到登錄頁(yè)面
.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)登錄失敗:

使用正確的密碼,響應(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)文章
idea 多模塊項(xiàng)目依賴父工程class找不到問(wèn)題的方法
這篇文章主要介紹了idea 多模塊項(xiàng)目依賴父工程class找不到問(wèn)題的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01
Java?獲取Zookeeper節(jié)點(diǎn)下所有數(shù)據(jù)詳細(xì)步驟
本文介紹了如何使用Java獲取ZooKeeper節(jié)點(diǎn)下所有數(shù)據(jù),實(shí)際應(yīng)用示例中,我們演示了如何從ZooKeeper節(jié)點(diǎn)下獲取配置信息并輸出到控制臺(tái),ZooKeeper是一個(gè)開源的分布式協(xié)調(diào)服務(wù),適用于分布式系統(tǒng)中的數(shù)據(jù)同步、配置管理、命名服務(wù)等功能,感興趣的朋友一起看看吧2024-11-11
idea啟動(dòng)Tomcat時(shí)控制臺(tái)亂碼的解決方法(親測(cè)有效)
最近在idea中啟動(dòng)tomcat出現(xiàn)控制臺(tái)亂碼問(wèn)題,嘗試了很多方法,最后終于解決了,所以下面這篇文章主要給大家介紹了關(guān)于idea啟動(dòng)Tomcat時(shí)控制臺(tái)亂碼的解決方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07
springboot vue完成編輯頁(yè)面發(fā)送接口請(qǐng)求功能
這篇文章主要為大家介紹了springboot+vue完成編輯頁(yè)發(fā)送接口請(qǐng)求功能,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
Java基礎(chǔ)高級(jí)綜合練習(xí)題撲克牌的創(chuàng)建
今天小編就為大家分享一篇關(guān)于Java基礎(chǔ)高級(jí)綜合練習(xí)題撲克牌的創(chuàng)建,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01

