Spring源代碼解析9:Spring Acegi框架鑒權(quán)的實現(xiàn)_第1頁
Spring源代碼解析9:Spring Acegi框架鑒權(quán)的實現(xiàn)_第2頁
Spring源代碼解析9:Spring Acegi框架鑒權(quán)的實現(xiàn)_第3頁
Spring源代碼解析9:Spring Acegi框架鑒權(quán)的實現(xiàn)_第4頁
Spring源代碼解析9:Spring Acegi框架鑒權(quán)的實現(xiàn)_第5頁
已閱讀5頁,還剩21頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論