版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
簡單分析一下SpringAcegi的源代碼實現(xiàn):的實現(xiàn)AuthenticationProcessingFilter啟動Web頁面的驗證過程-在AbstractProcessingFilter定義了整個驗證過程的模板:代碼1.public
void
doFilter(ServletRequest
request,
ServletResponse
response,
FilterChain
chain
2.
throws
IOException,
ServletException
{
3.
//這里檢驗是不是符合ServletRequest/SevletResponse的要求
4.
if
(!(request
instanceof
HttpServletRequest
{
5.
throw
new
ServletException("Can
only
process
HttpServletRequest";
6.
}
7.
8.
if
(!(response
instanceof
HttpServletResponse
{
9.
throw
new
ServletException("Can
only
process
HttpServletResponse";
10.
}
11.
12.
HttpServletRequest
httpRequest
=
(HttpServletRequest
request;
13.
HttpServletResponse
httpResponse
=
(HttpServletResponse
response;
14.
//根據(jù)HttpServletRequest和HttpServletResponse來進行驗證
15.
if
(requiresAuthentication(httpRequest,
httpResponse
{
16.
if
(logger.isDebugEnabled(
{
17.
logger.debug("Request
is
to
process
authentication";
18.
}
19.
//這里定義Acegi中的Authentication對象來持有相關(guān)的用戶驗證信息
20.
Authentication
authResult;
21.
22.
try
{
23.
onPreAuthentication(httpRequest,
httpResponse;
24.
//這里的具體驗證過程委托給子類完成,比如AuthenticationProcessingFilter來完成基于Web頁面的用戶驗證
25.
authResult
=
attemptAuthentication(httpRequest;
26.
}
catch
(AuthenticationException
failed
{
27.
//
Authentication
failed
28.
unsuccessfulAuthentication(httpRequest,
httpResponse,
failed;
29.
30.
return;
31.
}
32.
33.
//
Authentication
success
34.
if
(continueChainBeforeSuccessfulAuthentication
{
35.
chain.doFilter(request,
response;
36.
}
37.
//完成驗證后的后續(xù)工作,比如跳轉(zhuǎn)到相應(yīng)的頁面
38.
successfulAuthentication(httpRequest,
httpResponse,
authResult;
39.
40.
return;
41.
}
42.
43.
chain.doFilter(request,
response;
44.}
在AuthenticationProcessingFilter中的具體驗證過程是這樣的:代碼1.public
Authentication
attemptAuthentication(HttpServletRequest
request
2.
throws
AuthenticationException
{
3.
//這里從HttpServletRequest中得到用戶驗證的用戶名和密碼
4.
String
username
=
obtainUsername(request;
5.
String
password
=
obtainPassword(request;
6.
7.
if
(username
==
null
{
8.
username
=
"";
9.
}
10.
11.
if
(password
==
null
{
12.
password
=
"";
13.
}
14.
//這里根據(jù)得到的用戶名和密碼去構(gòu)造一個Authentication對象提供給AuthenticationManager進行驗證,里面包含了用戶的用戶名和密碼信息
15.
UsernamePasswordAuthenticationToken
authRequest
=
new
UsernamePasswordAuthenticationToken(username,
password;
16.
17.
//
Place
the
last
username
attempted
into
HttpSession
for
views
18.
request.getSession(.setAttribute(ACEGI_SECURITY_LAST_USERNAME_KEY,
username;
19.
20.
//
Allow
subclasses
to
set
the
"details"
property
21.
setDetails(request,
authRequest;
22.
//這里啟動AuthenticationManager進行驗證過程
23.
return
this.getAuthenticationManager(.authenticate(authRequest;
24.}
在Acegi框架中,進行驗證管理的主要類是AuthenticationManager,我們看看它是怎樣進行驗證管理的-驗證的調(diào)用入口是authenticate在AbstractAuthenticationManager的實現(xiàn)中:
//這是進行驗證的函數(shù),返回一個Authentication對象來記錄驗證的結(jié)果,其中包含了用戶的驗證信息,權(quán)限配置等,同時這個Authentication會以后被授權(quán)模塊使用代碼1.//如果驗證失敗,那么在驗證過程中會直接拋出異常
2.
public
final
Authentication
authenticate(Authentication
authRequest
3.
throws
AuthenticationException
{
4.
try
{//這里是實際的驗證處理,我們下面使用ProviderManager來說明具體的驗證過程,傳入的參數(shù)authRequest里面已經(jīng)包含了從HttpServletRequest中得到的用戶輸入的用戶名和密碼
5.
Authentication
authResult
=
doAuthentication(authRequest;
6.
copyDetails(authRequest,
authResult;
7.
8.
return
authResult;
9.
}
catch
(AuthenticationException
e
{
10.
e.setAuthentication(authRequest;
11.
throw
e;
12.
}
13.
}
在ProviderManager中進行實際的驗證工作,假設(shè)這里使用數(shù)據(jù)庫來存取用戶信息:代碼1.public
Authentication
doAuthentication(Authentication
authentication
2.
throws
AuthenticationException
{
3.
//這里取得配置好的provider鏈的迭代器,在配置的時候可以配置多個provider,這里我們配置的是DaoAuthenticationProvider來說明,
它使用數(shù)據(jù)庫來保存用戶的用戶名和密碼信息。
4.
Iterator
iter
=
providers.iterator(;
5.
6.
Class
toTest
=
authentication.getClass(;
7.
8.
AuthenticationException
lastException
=
null;
9.
10.
while
(iter.hasNext(
{
11.
AuthenticationProvider
provider
=
(AuthenticationProvider
iter.next(;
12.
13.
if
(provider.supports(toTest
{
14.
logger.debug("Authentication
attempt
using
"
+
provider.getClass(.getName(;
15.
//這個result包含了驗證中得到的結(jié)果信息
16.
Authentication
result
=
null;
17.
18.
try
{//這里是provider進行驗證處理的過程
19.
result
=
provider.authenticate(authentication;
20.
sessionController.checkAuthenticationAllowed(result;
21.
}
catch
(AuthenticationException
ae
{
22.
lastException
=
ae;
23.
result
=
null;
24.
}
25.
26.
if
(result
!=
null
{
27.
sessionController.registerSuccessfulAuthentication(result;
28.
publishEvent(new
AuthenticationSuccessEvent(result;
29.
30.
return
result;
31.
}
32.
}
33.
}
34.
35.
if
(lastException
==
null
{
36.
lastException
=
new
ProviderNotFoundException(messages.getMessage("ProviderMviderNotFound",
37.
new
Object[]
{toTest.getName(},
"No
AuthenticationProvider
found
for
{0}";
38.
}
39.
40.
//
這里發(fā)布事件來通知上下文的監(jiān)聽器
41.
String
className
=
exceptionMappings.getProperty(lastException.getClass(.getName(;
42.
AbstractAuthenticationEvent
event
=
null;
43.
44.
if
(className
!=
null
{
45.
try
{
46.
Class
clazz
=
getClass(.getClassLoader(.loadClass(className;
47.
Constructor
constructor
=
clazz.getConstructor(new
Class[]
{
48.
Authentication.class,
AuthenticationException.class
49.
};
50.
Object
obj
=
constructor.newInstance(new
Object[]
{authentication,
lastException};
51.
Assert.isInstanceOf(AbstractAuthenticationEvent.class,
obj,
"Must
be
an
AbstractAuthenticationEvent";
52.
event
=
(AbstractAuthenticationEvent
obj;
53.
}
catch
(ClassNotFoundException
ignored
{}
54.
catch
(NoSuchMethodException
ignored
{}
55.
catch
(IllegalAccessException
ignored
{}
56.
catch
(InstantiationException
ignored
{}
57.
catch
(InvocationTargetException
ignored
{}
58.
}
59.
60.
if
(event
!=
null
{
61.
publishEvent(event;
62.
}
else
{
63.
if
(logger.isDebugEnabled(
{
64.
logger.debug("No
event
was
found
for
the
exception
"
+
lastException.getClass(.getName(;
65.
}
66.
}
67.
68.
//
Throw
the
exception
69.
throw
lastException;
70.}
我們下面看看在DaoAuthenticationProvider是怎樣從數(shù)據(jù)庫中取出對應(yīng)的驗證信息進行用戶驗證的,在它的基類AbstractUserDetailsAuthenticationProvider定義了驗證的處理模板:代碼1.public
Authentication
authenticate(Authentication
authentication
2.
throws
AuthenticationException
{
3.
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class,
authentication,
4.
messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports",
5.
"Only
UsernamePasswordAuthenticationToken
is
supported";
6.
7.
//
這里取得用戶輸入的用戶名
8.
String
username
=
(authentication.getPrincipal(
==
null
?
"NONE_PROVIDED"
:
authentication.getName(;
9.
//
如果配置了緩存,從緩存中去取以前存入的用戶驗證信息
-
這里是UserDetail,是服務(wù)器端存在數(shù)據(jù)庫里的用戶信息,這樣就不用每次都去數(shù)據(jù)庫中取了
10.
boolean
cacheWasUsed
=
true;
11.
UserDetails
user
=
this.userCache.getUserFromCache(username;
12.
//沒有取到,設(shè)置標(biāo)志位,下面會把這次取到的服務(wù)器端用戶信息存入緩存中去
13.
if
(user
==
null
{
14.
cacheWasUsed
=
false;
15.
16.
try
{//這里是調(diào)用UserDetailService去取用戶數(shù)據(jù)庫里信息的地方
17.
user
=
retrieveUser(username,
(UsernamePasswordAuthenticationToken
authentication;
18.
}
catch
(UsernameNotFoundException
notFound
{
19.
if
(hideUserNotFoundExceptions
{
20.
throw
new
BadCredentialsException(messages.getMessage(
21.
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad
credentials";
22.
}
else
{
23.
throw
notFound;
24.
}
25.
}
26.
27.
Assert.notNull(user,
"retrieveUser
returned
null
-
a
violation
of
the
interface
contract";
28.
}
29.
30.
if
(!user.isAccountNonLocked(
{
31.
throw
new
LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
32.
"User
account
is
locked";
33.
}
34.
35.
if
(!user.isEnabled(
{
36.
throw
new
DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
37.
"User
is
disabled";
38.
}
39.
40.
if
(!user.isAccountNonExpired(
{
41.
throw
new
AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
42.
"User
account
has
expired";
43.
}
44.
45.
//
This
check
must
come
here,
as
we
don't
want
to
tell
users
46.
//
about
account
status
unless
they
presented
the
correct
credentials
47.
try
{//這里是驗證過程,在retrieveUser中從數(shù)據(jù)庫中得到用戶的信息,在additionalAuthenticationChecks中進行對比用戶輸入和服務(wù)器端的用戶信息
48.
//如果驗證通過,那么構(gòu)造一個Authentication對象來讓以后的授權(quán)使用,如果驗證不通過,直接拋出異常結(jié)束鑒權(quán)過程
49.
additionalAuthenticationChecks(user,
(UsernamePasswordAuthenticationToken
authentication;
50.
}
catch
(AuthenticationException
exception
{
51.
if
(cacheWasUsed
{
52.
//
There
was
a
problem,
so
try
again
after
checking
53.
//
we're
using
latest
data
(ie
not
from
the
cache
54.
cacheWasUsed
=
false;
55.
user
=
retrieveUser(username,
(UsernamePasswordAuthenticationToken
authentication;
56.
additionalAuthenticationChecks(user,
(UsernamePasswordAuthenticationToken
authentication;
57.
}
else
{
58.
throw
exception;
59.
}
60.
}
61.
62.
if
(!user.isCredentialsNonExpired(
{
63.
throw
new
CredentialsExpiredException(messages.getMessage(
64.
"AbstractUserDetailsAuthenticationProvider.credentialsExpired",
"User
credentials
have
expired";
65.
}
66.
//根據(jù)前面的緩存結(jié)果決定是不是要把當(dāng)前的用戶信息存入緩存以供下次驗證使用
67.
if
(!cacheWasUsed
{
68.
this.userCache.putUserInCache(user;
69.
}
70.
71.
Object
principalToReturn
=
user;
72.
73.
if
(forcePrincipalAsString
{
74.
principalToReturn
=
user.getUsername(;
75.
}
76.
//最后返回Authentication記錄了驗證結(jié)果供以后的授權(quán)使用
77.
return
createSuccessAuthentication(principalToReturn,
authentication,
user;
78.}
79.//這是是調(diào)用UserDetailService去加載服務(wù)器端用戶信息的地方,從什么地方加載要看設(shè)置,這里我們假設(shè)由JdbcDaoImp來從數(shù)據(jù)中進行加載
80.protected
final
UserDetails
retrieveUser(String
username,
UsernamePasswordAuthenticationToken
authentication
81.
throws
AuthenticationException
{
82.
UserDetails
loadedUser;
83.
//這里調(diào)用UserDetailService去從數(shù)據(jù)庫中加載用戶驗證信息,同時返回從數(shù)據(jù)庫中返回的信息,這些信息放到了UserDetails對象中去了
84.
try
{
85.
loadedUser
=
this.getUserDetailsService(.loadUserByUsername(username;
86.
}
catch
(DataAccessException
repositoryProblem
{
87.
throw
new
AuthenticationServiceException(repositoryProblem.getMessage(,
repositoryProblem;
88.
}
89.
90.
if
(loadedUser
==
null
{
91.
throw
new
AuthenticationServiceException(
92.
"UserDetailsService
returned
null,
which
is
an
interface
contract
violation";
93.
}
94.
return
loadedUser;
95.}
下面我們重點分析一下JdbcDaoImp這個類來看看具體是怎樣從數(shù)據(jù)庫中得到用戶信息的:代碼1.public
class
JdbcDaoImpl
extends
JdbcDaoSupport
implements
UserDetailsService
{
2.
//~
Static
fields/initializers
=====================================================================================
3.
//這里是預(yù)定義好的對查詢語句,對應(yīng)于默認(rèn)的數(shù)據(jù)庫表結(jié)構(gòu),也可以自己定義查詢語句對應(yīng)特定的用戶數(shù)據(jù)庫驗證表的設(shè)計
4.
public
static
final
String
DEF_USERS_BY_USERNAME_QUERY
=
5.
"SELECT
username,password,enabled
FROM
users
WHERE
username
=
?";
6.
public
static
final
String
DEF_AUTHORITIES_BY_USERNAME_QUERY
=
7.
"SELECT
username,authority
FROM
authorities
WHERE
username
=
?";
8.
9.
//~
Instance
fields
================================================================================================
10.
//這里使用Spring
JDBC來進行數(shù)據(jù)庫操作
11.
protected
MappingSqlQuery
authoritiesByUsernameMapping;
12.
protected
MappingSqlQuery
usersByUsernameMapping;
13.
private
String
authoritiesByUsernameQuery;
14.
private
String
rolePrefix
=
"";
15.
private
String
usersByUsernameQuery;
16.
private
boolean
usernameBasedPrimaryKey
=
true;
17.
18.
//~
Constructors
===================================================================================================
19.
//在初始化函數(shù)中把查詢語句設(shè)置為預(yù)定義的SQL語句
20.
public
JdbcDaoImpl(
{
21.
usersByUsernameQuery
=
DEF_USERS_BY_USERNAME_QUERY;
22.
authoritiesByUsernameQuery
=
DEF_AUTHORITIES_BY_USERNAME_QUERY;
23.
}
24.
25.
//~
Methods
========================================================================================================
26.
27.
protected
void
addCustomAuthorities(String
username,
List
authorities
{}
28.
29.
public
String
getAuthoritiesByUsernameQuery(
{
30.
return
authoritiesByUsernameQuery;
31.
}
32.
33.
public
String
getRolePrefix(
{
34.
return
rolePrefix;
35.
}
36.
37.
public
String
getUsersByUsernameQuery(
{
38.
return
usersByUsernameQuery;
39.
}
40.
41.
protected
void
initDao(
throws
ApplicationContextException
{
42.
initMappingSqlQueries(;
43.
}
44.
45.
/**
46.
*
Extension
point
to
allow
other
MappingSqlQuery
objects
to
be
substituted
in
a
subclass
47.
*/
48.
protected
void
initMappingSqlQueries(
{
49.
this.usersByUsernameMapping
=
new
UsersByUsernameMapping(getDataSource(;
50.
this.authoritiesByUsernameMapping
=
new
AuthoritiesByUsernameMapping(getDataSource(;
51.
}
52.
53.
public
boolean
isUsernameBasedPrimaryKey(
{
54.
return
usernameBasedPrimaryKey;
55.
}
56.
//這里是取得數(shù)據(jù)庫用戶信息的具體過程
57.
public
UserDetails
loadUserByUsername(String
username
58.
throws
UsernameNotFoundException,
DataAccessException
{
59.
//根據(jù)用戶名在用戶表中得到用戶信息,包括用戶名,密碼和用戶是否有效的信息
60.
List
users
=
usersByUsernameMapping.execute(username;
61.
62.
if
(users.size(
==
0
{
63.
throw
new
UsernameNotFoundException("User
not
found";
64.
}
65.
//取集合中的第一個作為有效的用戶對象
66.
UserDetails
user
=
(UserDetails
users.get(0;
//
contains
no
GrantedAuthority[]
67.
//這里在權(quán)限表中去取得用戶的權(quán)限信息,同樣的返回一個權(quán)限集合對應(yīng)于這個用戶
68.
List
dbAuths
=
authoritiesByUsernameMapping.execute(user.getUsername(;
69.
70.
addCustomAuthorities(user.getUsername(,
dbAuths;
71.
72.
if
(dbAuths.size(
==
0
{
73.
throw
new
UsernameNotFoundException("User
has
no
GrantedAuthority";
74.
}
75.
//這里根據(jù)得到的權(quán)限集合來配置返回的User對象供以后使用
76.
GrantedAuthority[]
arrayAuths
=
(GrantedAuthority[]
dbAuths.toArray(new
GrantedAuthority[dbAuths.size(];
77.
78.
String
returnUsername
=
user.getUsername(;
79.
80.
if
(!usernameBasedPrimaryKey
{
81.
returnUsername
=
username;
82.
}
83.
84.
return
new
User(returnUsername,
user.getPassword(,
user.isEnabled(,
true,
true,
true,
arrayAuths;
85.
}
86.
87.
public
void
setAuthoritiesByUsernameQuery(String
queryString
{
88.
authoritiesByUsernameQuery
=
queryString;
89.
}
90.
91.
public
void
setRolePrefix(String
rolePrefix
{
92.
this.rolePrefix
=
rolePrefix;
93.
}
94.
95.
public
void
setUsernameBasedPrimaryKey(boolean
usernameBasedPrimaryKey
{
96.
this.usernameBasedPrimaryKey
=
usernameBasedPrimaryKey;
97.
}
98.
99.
public
void
setUsersByUsernameQuery(String
usersByUsernameQueryString
{
100.
this.usersByUsernameQuery
=
usersByUsernameQueryString;
101.
}
102.
103.
//~
Inner
Classes
==================================================================================================
104.
105.
/**
106.
*
這里是調(diào)用Spring
JDBC的數(shù)據(jù)庫操作,具體可以參考對JDBC的分析,這個類的作用是把數(shù)據(jù)庫查詢得到的記錄集合轉(zhuǎn)換為對象集合
-
一個很簡單的O/R實現(xiàn)
107.
*/
108.
protected
class
AuthoritiesByUsernameMapping
extends
MappingSqlQuery
{
109.
protected
AuthoritiesByUsernameMapping(DataSource
ds
{
110.
super(ds,
authoritiesByUsernameQuery;
111.
declareParameter(new
SqlParameter(Types.VARCHAR;
112.
compile(;
113.
}
114.
115.
protected
Object
mapRow(ResultSet
rs,
int
rownum
116.
throws
SQLException
{
117.
String
roleName
=
rolePrefix
+
rs.getString(2;
118.
GrantedAuthorityImpl
authority
=
new
GrantedAuthorityImpl(roleName;
119.
120.
return
authority;
121.
}
122.
}
123.
124.
/**
125.
*
Query
object
to
look
up
a
user.
126.
*/
127.
protected
class
UsersByUsernameMapping
extends
MappingSqlQuery
{
128.
protected
UsersByUsernameMapping(DataSource
ds
{
129.
super(ds,
usersByUsernameQuery;
130.
declareParameter(new
SqlParameter(Types.VARCHAR;
131.
compile(;
132.
}
133.
134.
protected
Object
mapRow(ResultSet
rs,
int
rownum
135.
throws
SQLException
{
136.
String
username
=
rs.getString(1;
137.
String
password
=
rs.getString(2;
138.
boolean
enabled
=
rs.getBoolean(3;
139.
UserDetails
user
=
new
User(usernam
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026山東菏澤市東明縣部分事業(yè)單位招聘專業(yè)技術(shù)人員23人參考題庫新版
- 服務(wù)競爭分析細(xì)則
- 生成式人工智能應(yīng)用效果評估與持續(xù)優(yōu)化方案
- 2025湖南永州市新田縣消防救援大隊招錄3名政府專職消防員備考題庫附答案
- 2025黑龍江哈爾濱市平房區(qū)平房鎮(zhèn)衛(wèi)生院招聘醫(yī)療技術(shù)工作人員2人參考題庫附答案
- 2025年貴陽職業(yè)技術(shù)學(xué)院輔導(dǎo)員考試筆試真題匯編附答案
- 2026上??萍即髮W(xué)細(xì)胞與基因治療技術(shù)轉(zhuǎn)化平臺招聘運維工程師1名參考題庫含答案
- 2026上海金橋經(jīng)濟技術(shù)開發(fā)區(qū)管理委員會文員公開招聘1人備考題庫含答案
- 大型儲罐罐壁開孔應(yīng)力分析報告審查
- 省級示范護林員申請書
- 2025《上市公司治理準(zhǔn)則》解讀課件
- 音樂口風(fēng)琴課件
- 閥門常見故障原因及預(yù)防處理方法
- 2025年重慶市中考物理真題(附答案)
- 2025年售電專業(yè)面試題及答案大全
- (高清版)DB11∕T 2440-2025 學(xué)校食堂病媒生物防制規(guī)范
- 隧道工程施工資源配置計劃策劃
- DB51∕T 705-2023 四川主要造林樹種苗木質(zhì)量分級
- 《T/CNEA核電廠危險化學(xué)品安全管理指南-編制說明》
- 校園文印室外包服務(wù)投標(biāo)方案(技術(shù)標(biāo))
- 博士課程-中國馬克思主義與當(dāng)代(2024年修)習(xí)題答案
評論
0/150
提交評論