日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

oracle access manager token,AuthenticationManager验证原理

發布時間:2024/9/3 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 oracle access manager token,AuthenticationManager验证原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

AuthenticationManager相關類圖

AuthenticationManager驗證過程

AuthenticationManager驗證過程涉及到的類和接口較多,我們就從這里開始逐一分析,首先我手畫了一張圖作為索引,這張圖說明了各個類和接口之間的關系。

AuthenticationManager 為認證管理接口類,其定義了認證方法authenticate()。

ProviderManager 為驗證管理類,實現了接口AuthenticationManager ,并在認證方法authenticate() 中將身份認證委托給具有認證資格的AuthenticationProvider 進行身份認證。

從上圖中我們可以看到AuthenticationManager的實現類有很多,至于為什么我只提及到ProviderManager,有時間的小伙伴可以進行源碼跟蹤就能發現。

ProviderManager的成員變量

關于AuthenticationEventPublisher不懂的小伙伴可以查看Security中的認證事件發布器 。

providers存儲了一個 AuthenticationProvider 類型的list。和Security中的配置文件相對應。

MessageSourceAccessor一個國際化消息來源訪問器,Security中用于信息提示。

AuthenticationProvider

接口認證類,定義了認證方法authenticate() 。

AbstractUserDetailsAuthenticationProvider 為認證抽象類,實現了接口 AuthenticationProvider 定義的認證方法 authenticate()。還定義了抽象方法 retrieveUser() 用于查詢數據庫用戶信息,以及抽象方法 additionalAuthenticationChecks() 用作額外的身份驗證檢查。

DaoAuthenticationProvider

繼承自抽象類AbstractUserDetailsAuthenticationProvider,實現了該類的方法 retrieveUser() 和 additionalAuthenticationChecks()。

DaoAuthenticationProvider 中還具有四個成員變量,分別是

USER_NOT_FOUND_PASSWORD

顧名思義,該變量是與PasswordEncoder一同使用的,當Security未找到用戶時,用于PasswordEncoder.matches()執行的明文密碼,以防止惡意用戶確定用戶名是否有效的旁路攻擊的可能性。

PasswordEncoder

密碼編碼器,Security中的主要作用是用于將明文密碼轉換成密文,它采用SHA-256算法,迭代1024次,使用一個密鑰(site-wide secret)以及8位隨機鹽對原密碼進行加密。

userNotFoundEncodedPassword

同上方USER_NOT_FOUND_PASSWORD一致,只不過Security將其修飾為volatile的,確保了該變量不會因為編譯器的優化而被省略。

關于volatile關鍵字不懂的請查看volatile理解

UserDetailsService

這個變量相信很多人都知道,不做過多的解釋,Security中用于查詢用戶詳細信息的接口

UserDetailsPasswordService

顧名思義,該接口用于修改用戶的密碼,只有在使用持久存儲庫時才有效,基于內存的方式會拋異常。(用處不大,只做了解即可)

流程分析

static final class AuthenticationManagerDelegator implements AuthenticationManager {

private AuthenticationManagerBuilder delegateBuilder;

private AuthenticationManager delegate;

private final Object delegateMonitor = new Object();

AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) {

Assert.notNull(delegateBuilder, "delegateBuilder cannot be null");

this.delegateBuilder = delegateBuilder;

}

@Override

public Authentication authenticate(Authentication authentication)

throws AuthenticationException {

if (this.delegate != null) {

return this.delegate.authenticate(authentication);

}

synchronized (this.delegateMonitor) {

if (this.delegate == null) {

this.delegate = this.delegateBuilder.getObject();

this.delegateBuilder = null;

}

}

return this.delegate.authenticate(authentication);

}

@Override

public String toString() {

return "AuthenticationManagerDelegator [delegate=" + this.delegate + "]";

}

}

1、Security認證的入口為AuthenticationManager的authenticate()方法,從上面代碼中我們可以看出,AuthenticationManagerDelegator使用了單例模式來防止AuthenticationManager在初始化時發生無限遞歸,因此我們只分析上方的兩個實現類OAuth2AuthenticationManager和ProviderManager。

OAuth2AuthenticationManager

OAuth2AuthenticationManager的authenticate()的方法代碼如下:

public Authentication authenticate(Authentication authentication) throws AuthenticationException {

if (authentication == null) {

throw new InvalidTokenException("Invalid token (token not found)");

}

(1) String token = (String) authentication.getPrincipal();

(2) OAuth2Authentication auth = tokenServices.loadAuthentication(token);

if (auth == null) {

throw new InvalidTokenException("Invalid token: " + token);

}

Collection resourceIds = auth.getOAuth2Request().getResourceIds();

if (resourceId != null && resourceIds != null && !resourceIds.isEmpty() && !resourceIds.contains(resourceId)) {

throw new OAuth2AccessDeniedException("Invalid token does not contain resource id (" + resourceId + ")");

}

(3) checkClientDetails(auth);

if (authentication.getDetails() instanceof OAuth2AuthenticationDetails) {

OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();

// Guard against a cached copy of the same details

if (!details.equals(auth.getDetails())) {

// Preserve the authentication details from the one loaded by token services

details.setDecodedDetails(auth.getDetails());

}

}

auth.setDetails(authentication.getDetails());

auth.setAuthenticated(true);

return auth;

}

private void checkClientDetails(OAuth2Authentication auth) {

if (clientDetailsService != null) {

ClientDetails client;

try {

client = clientDetailsService.loadClientByClientId(auth.getOAuth2Request().getClientId());

}

catch (ClientRegistrationException e) {

throw new OAuth2AccessDeniedException("Invalid token contains invalid client id");

}

Set allowed = client.getScope();

for (String scope : auth.getOAuth2Request().getScope()) {

if (!allowed.contains(scope)) {

throw new OAuth2AccessDeniedException(

"Invalid token contains disallowed scope (" + scope + ") for this client");

}

}

}

}

OAuth2AuthenticationManager用于集成了OAuth2.0時使用的,如果沒有用到,可以忽略。

其中:

(1)處的代碼,期望傳入的身份驗證請求具有一個主體值,該主體值是一個訪問令牌值(一般在(authorization header)請求頭中)

(2)處從ResourceServerTokenServices通過查詢數據庫中 oauth_client_details該表,加載身份驗證。

通過(3)處檢查資源id是否包含在授權請求中。檢查通過之后封裝OAuth2認證實體返回給UsernamePasswordAuthenticationFilter以確定認證成功或失敗。

ProviderManager

ProviderManager的authenticate()的方法代碼如下:

public Authentication authenticate(Authentication authentication)

throws AuthenticationException {

Class extends Authentication> toTest = authentication.getClass();

AuthenticationException lastException = null;

AuthenticationException parentException = null;

Authentication result = null;

Authentication parentResult = null;

boolean debug = logger.isDebugEnabled();

(1) for (AuthenticationProvider provider : getProviders()) {

if (!provider.supports(toTest)) {

continue;

}

if (debug) {

logger.debug("Authentication attempt using "

+ provider.getClass().getName());

}

try {

(2) result = provider.authenticate(authentication);

if (result != null) {

copyDetails(authentication, result);

break;

}

}

catch (AccountStatusException | InternalAuthenticationServiceException e) {

prepareException(e, authentication);

// SEC-546: Avoid polling additional providers if auth failure is due to

// invalid account status

throw e;

} catch (AuthenticationException e) {

lastException = e;

}

}

if (result == null && parent != null) {

// Allow the parent to try.

try {

result = parentResult = parent.authenticate(authentication);

}

catch (ProviderNotFoundException e) {

// ignore as we will throw below if no other exception occurred prior to

// calling parent and the parent

// may throw ProviderNotFound even though a provider in the child already

// handled the request

}

catch (AuthenticationException e) {

lastException = parentException = e;

}

}

if (result != null) {

if (eraseCredentialsAfterAuthentication

&& (result instanceof CredentialsContainer)) {

// Authentication is complete. Remove credentials and other secret data

// from authentication

((CredentialsContainer) result).eraseCredentials();

}

// If the parent AuthenticationManager was attempted and successful than it will publish an AuthenticationSuccessEvent

// This check prevents a duplicate AuthenticationSuccessEvent if the parent AuthenticationManager already published it

if (parentResult == null) {

eventPublisher.publishAuthenticationSuccess(result);

}

return result;

}

// Parent was null, or didn't authenticate (or throw an exception).

if (lastException == null) {

lastException = new ProviderNotFoundException(messages.getMessage(

"ProviderManager.providerNotFound",

new Object[] { toTest.getName() },

"No AuthenticationProvider found for {0}"));

}

// If the parent AuthenticationManager was attempted and failed than it will publish an AbstractAuthenticationFailureEvent

// This check prevents a duplicate AbstractAuthenticationFailureEvent if the parent AuthenticationManager already published it

if (parentException == null) {

prepareException(lastException, authentication);

}

throw lastException;

}

其中:

(1)處的代碼從ProviderManager的屬性providers[List]中通過for循環拿到支持該類認證的AuthenticationProvider用于認證處理。

(2)處的代碼,對用戶進行身份認證,認證過程如下所示。

在上面(2)處的代碼,使用了AbstractUserDetailsAuthenticationProvider的authenticate()方法,接下來具體分析該方法,代碼如下:

public Authentication authenticate(Authentication authentication)

throws AuthenticationException {

Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,

() -> messages.getMessage(

"AbstractUserDetailsAuthenticationProvider.onlySupports",

"Only UsernamePasswordAuthenticationToken is supported"));

// Determine username

String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED"

: authentication.getName();

boolean cacheWasUsed = true;

UserDetails user = this.userCache.getUserFromCache(username);

if (user == null) {

cacheWasUsed = false;

try {

(1) user = retrieveUser(username,

(UsernamePasswordAuthenticationToken) authentication);

}

catch (UsernameNotFoundException notFound) {

logger.debug("User '" + username + "' not found");

if (hideUserNotFoundExceptions) {

throw new BadCredentialsException(messages.getMessage(

"AbstractUserDetailsAuthenticationProvider.badCredentials",

"Bad credentials"));

}

else {

throw notFound;

}

}

Assert.notNull(user,

"retrieveUser returned null - a violation of the interface contract");

}

try {

preAuthenticationChecks.check(user);

(2) additionalAuthenticationChecks(user,

(UsernamePasswordAuthenticationToken) authentication);

}

catch (AuthenticationException exception) {

if (cacheWasUsed) {

// There was a problem, so try again after checking

// we're using latest data (i.e. not from the cache)

cacheWasUsed = false;

user = retrieveUser(username,

(UsernamePasswordAuthenticationToken) authentication);

preAuthenticationChecks.check(user);

additionalAuthenticationChecks(user,

(UsernamePasswordAuthenticationToken) authentication);

}

else {

throw exception;

}

}

postAuthenticationChecks.check(user);

if (!cacheWasUsed) {

this.userCache.putUserInCache(user);

}

Object principalToReturn = user;

if (forcePrincipalAsString) {

principalToReturn = user.getUsername();

}

(3) return createSuccessAuthentication(principalToReturn, authentication, user);

}

(3)處創建一個成功的身份認證令牌并將用戶認證信息其放置到UsernamePasswordAuthenticationToken中。

查看源碼我們得知,AbstractUserDetailsAuthenticationProvider的(1)處和(2)處調用的方法沒有具體的實現,因此我們接下來分析它的子類DaoAuthenticationProvider

retrieveUser()

protected final UserDetails retrieveUser(String username,

UsernamePasswordAuthenticationToken authentication)

throws AuthenticationException {

prepareTimingAttackProtection();

try {

(1) UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);

if (loadedUser == null) {

throw new InternalAuthenticationServiceException(

"UserDetailsService returned null, which is an interface contract violation");

}

return loadedUser;

}

catch (UsernameNotFoundException ex) {

mitigateAgainstTimingAttack(authentication);

throw ex;

}

catch (InternalAuthenticationServiceException ex) {

throw ex;

}

catch (Exception ex) {

throw new InternalAuthenticationServiceException(ex.getMessage(), ex);

}

}

(1)處調用DaoAuthenticationProvider成員變量UserDetailsService的方法loadUserByUsername()從數據庫中加載用戶詳細信息(用過Security的對此處應該是很熟悉了)

additionalAuthenticationChecks()

protected void additionalAuthenticationChecks(UserDetails userDetails,

UsernamePasswordAuthenticationToken authentication)

throws AuthenticationException {

if (authentication.getCredentials() == null) {

logger.debug("Authentication failed: no credentials provided");

throw new BadCredentialsException(messages.getMessage(

"AbstractUserDetailsAuthenticationProvider.badCredentials",

"Bad credentials"));

}

(1) String presentedPassword = authentication.getCredentials().toString();

(2) if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {

logger.debug("Authentication failed: password does not match stored value");

throw new BadCredentialsException(messages.getMessage(

"AbstractUserDetailsAuthenticationProvider.badCredentials",

"Bad credentials"));

}

}

(1)處從UsernamePasswordAuthenticationToken中調出了密碼,再由(2)處通過調用成員變量passwordEncoder對其密碼進行驗證。

以上就是AuthenticationManager的驗證大致流程,由于本人能力有限,如有錯誤,還請各位大佬多多包涵并在評論區進行留言指正,我會一一回復。

總結

以上是生活随笔為你收集整理的oracle access manager token,AuthenticationManager验证原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 少妇熟女视频一区二区三区 | 国产精品视频99 | 日韩欧美国产亚洲 | 91九色高潮 | 久久97精品久久久久久久不卡 | 久久夜夜夜 | 午夜精品久久久久 | 99热最新网址 | 欧美日韩激情 | 成年人黄色免费视频 | 最近最新最好看的2019 | www.在线国产 | 成人一区在线观看 | 国产在线伊人 | xxxx色 | 夜夜爽天天爽 | 一级大片在线观看 | 牛牛av国产一区二区 | 爱情岛论坛自拍亚洲品质极速最新章 | 久久国产一 | 亚洲av无码国产精品久久久久 | 色噜噜狠狠狠综合曰曰曰88av | 精品国产丝袜一区二区三区乱码 | 最新免费黄色网址 | 亚欧乱色| 免费av网站在线看 | 国产精品99久久久久久宅男 | 日本少妇影院 | 成年人免费网 | 欧美天堂网站 | 91插插插影库永久免费 | 日韩av在线影院 | 青娱乐免费在线视频 | 亚洲18在线看污www麻豆 | 色婷婷国产精品综合在线观看 | 歪歪视频在线观看 | 欧美黄色大片免费观看 | 国产第3页 | 羞羞网站在线看 | 激情视频网址 | 91麻豆网 | 91porn在线| 成人免费黄 | 国产在线国偷精品免费看 | 手机在线看片国产 | 日韩欧美视频在线免费观看 | 爆乳2把你榨干哦ova在线观看 | 国产一级淫片免费 | 91精品国产综合久久香蕉 | 日干夜干天天干 | 夜夜撸影院 | 日本精品在线一区 | 91视频在| 欧美日韩精品一区二区三区蜜桃 | 欧美日韩在线观看一区二区 | 波多野结衣国产 | 国产精品一区二区久久毛片 | 亚洲区av| 日批免费网站 | 国产福利久久久 | 中文字幕日日夜夜 | aa视频网站 | 黄色污污视频网站 | 国产精品久久久久久久久久小说 | 蜜臀久久99精品久久久久久 | 亚洲高清色图 | 国产草草影院ccyycom | 女人18毛片一区二区三区 | 伊人国产在线 | 无码精品人妻一区二区三区影院 | 9l视频自拍九色9l视频 | 原创真实夫妻啪啪av | 探花视频在线观看 | 国产无遮挡又黄又爽又色视频 | 性一交一乱一伧国产女士spa | 91视频久久| 痴汉电车在线观看 | 清纯唯美亚洲 | 中文字幕导航 | 中文字幕在线观看二区 | 少妇大叫太粗太大爽一区二区 | 在线观看视频中文字幕 | 老司机一区 | 男人的天堂av网 | 黄色av网址大全 | 国产在线视频导航 | 丝袜美腿av在线 | 人人人人干 | 亚洲免费高清 | 久久人人爽爽人人爽人人片av | 黄色免费小视频 | 精东传媒在线 | 精品人妻无码一区二区三区蜜桃一 | 日本一级免费视频 | 一区二区三区四区免费视频 | 亚洲精品一区二区三区蜜臀 | 免费一级特黄毛大片 | 国产一区av在线 | a一级免费视频 |