<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在瞭解過Security的認證器後,如果想自定義登陸,只要實現AuthenticationProvider還有對應的Authentication就可以了
首先要建立一個自定義的Authentication,Security提供了一個Authentication的子類AbstractAuthenticationToken
我們實現這個類可以了,他已經實現了Authentication的一些方法
public class NamePassAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = 520L; private final Object principal; private Object credentials; //提供第一次進來的構造方法 public NamePassAuthenticationToken(Object principal, Object credentials) { super((Collection)null); this.principal = principal; this.credentials = credentials; this.setAuthenticated(false); } //提供填充Authentication的構造方法 public NamePassAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) { super(authorities); this.principal = principal; this.credentials = credentials; super.setAuthenticated(true); } @Override public Object getCredentials() { return this.credentials; } @Override public Object getPrincipal() { return this.principal; } @Override public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { if (isAuthenticated) { throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); } else { super.setAuthenticated(false); } } @Override public void eraseCredentials() { super.eraseCredentials(); this.credentials = null; } }
這個類關鍵就是一個是認證的,一個沒認證的的構造器
接著是AuthenticationProvider,需要實現他的authenticate方法
@Setter public class NamePassAuthenticationProvider implements AuthenticationProvider { private CustomUserDetailsService userDetailsService; private PasswordEncoder passwordEncoder; @Override //具體認證邏輯 public Authentication authenticate(Authentication authentication) { NamePassAuthenticationToken authenticationToken = (NamePassAuthenticationToken) authentication; String username = (String) authenticationToken.getPrincipal(); String password = (String) authenticationToken.getCredentials(); //讓具體認證類去認證 UserDetails user = userDetailsService.loadUserByUsername(username); boolean matches = passwordEncoder.matches(password, user.getPassword()); if (!matches) { ResMsg.throwException(AuthExceptionGroup.AUTH_ERROR); } //填充Authentication NamePassAuthenticationToken authenticationResult = new NamePassAuthenticationToken(user, password, user.getAuthorities()); authenticationResult.setDetails(authenticationToken.getDetails()); return authenticationResult; } @Override //指定具體的Authentication //根據你指定的Authentication來找到具體的Provider public boolean supports(Class<?> authentication) { return NamePassAuthenticationToken.class.isAssignableFrom(authentication); } }
接著就是填充設定了
@Component public class NamePassAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> { @Autowired private CustomUserDetailsService customUserDetailsService; @Autowired private PasswordEncoder passwordEncoder; @Override public void configure(HttpSecurity http) { //phonePass provider NamePassAuthenticationProvider provider = new NamePassAuthenticationProvider(); provider.setUserDetailsService(customUserDetailsService); provider.setPasswordEncoder(passwordEncoder); http.authenticationProvider(provider); } }
接下來就是匯入設定了
通常都會有一個實現了WebSecurityConfigurerAdapter的設定類
把設定類注入進來
@Autowired private NamePassAuthenticationSecurityConfig namePassAuthenticationSecurityConfig; protected void configure(HttpSecurity http) throws Exception { http.apply(namePassAuthenticationSecurityConfig); }
UserDetailsService是具體的認證實現類
這個類就非常熟悉了,只需要實現他的loadUserByUsername方法,就可以實現認證了
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { AuthmsViewAccount account = accountService.getAccount(username); if(account == null) { ResMsg.throwException(AUTH_ERROR); } if (account.getStatus() != 1) { ResMsg.throwException(ACCOUNT_HAS_BANED); } String spliceStaffInfo = String.format("%d-%s",account.getAccountId(),account.getUsername()); //只要Collection<? extends GrantedAuthority> authorities //這個引數不為空,就表明認證通過,所以空集合也可以通過 return new User(spliceStaffInfo,account.getPassword(), AuthorityUtils.NO_AUTHORITIES); }
把認證結果填充到上下文中
如果結合了Token,那麼需要從token中識別該使用者
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { String bearerToken = resolveToken(request); if (bearerToken != null && !"".equals(bearerToken.trim()) && SecurityContextHolder.getContext().getAuthentication() == null) { //從redis中獲取該使用者 NamePassAuthenticationToken namePassAuthenticationToken = authRedisHelper.get(bearerToken); if(namePassAuthenticationToken != null) { //將資訊儲存到上下文中 SecurityContextHolder.getContext().setAuthentication(namePassAuthenticationToken); } } chain.doFilter(request, response); } private String resolveToken(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) { return bearerToken.substring(7); } return null; }
public NamePassAuthenticationToken get(String bearerToken){ String spliceStaffInfo = (String)redisRepository.get(formatKey(bearerToken)); if(spliceStaffInfo == null) { return null; } return new NamePassAuthenticationToken(new AuthStaff(spliceStaffInfo),null,AuthorityUtils.NO_AUTHORITIES); }
在登入的時候,就需要用到這個自定義的認證器了
// 通過使用者名稱和密碼建立一個 Authentication 認證物件,實現類為 NamePassAuthenticationToken NamePassAuthenticationToken authenticationToken = new NamePassAuthenticationToken(user.getUsername(), user.getPassword()); //通過 AuthenticationManager(預設實現為ProviderManager)的authenticate方法驗證 Authentication 物件 //AuthenticationManager會通過你傳入的authenticationToken來找到具體的Provider Authentication authentication = authenticationManager.authenticate(authenticationToken); //填充使用者資訊到secrity中的user裡 User principal = (User) authentication.getPrincipal(); //獲取認證後的資訊 NamePassAuthenticationToken namePassAuthenticationToken = new NamePassAuthenticationToken(new AuthStaff(principal.getUsername()), null, authentication.getAuthorities()); // 生成token String bearerToken = IdUtil.fastSimpleUUID(); // 載入到reids authRedisHelper.set(bearerToken, namePassAuthenticationToken);
這樣就實現了自定義的認證器了
到此這篇關於Spring Security自定義認證器的文章就介紹到這了,更多相關Spring Security自定義認證器內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45