acegi
源碼學(xué)習(xí)之用戶(hù)登錄篇
一、查看
applicationContext-acegi-security.xml
配置文件,涉及到登錄的配置為:
?1
.
<
bean
id
=
"authenticationProcessingFilter"
class
=
"org.javajohn.test.plugins.security.UserAuthenticationProcessingFilter"
>
???????
<
property
name
=
"authenticationManager"
ref
=
"authenticationManager"
/>
???????
<
property
name
=
"authenticationFailureUrl"
>
???????????
<
value
>
/login.jsp?login_error=1
</
value
>
???????
</
property
>
???????
<
property
name
=
"defaultTargetUrl"
>
???????????
<
value
>
/index.jsp
</
value
>
???????
</
property
>
???????
<
property
name
=
"filterProcessesUrl"
>
???????????
<
value
>
/j_acegi_security_check
</
value
>
???????
</
property
>
???????
<
property
name
=
"userManager"
ref
=
"userManager"
/>
???????
<
property
name
=
"rememberMeServices"
ref
=
"rememberMeServices"
/>
???????
<
property
name
=
"exceptionMappings"
>
???????????
<
value
>
??????????????? org.acegisecurity.AuthenticationException=/login.jsp?login_error=user_psw_error
??????????????? org.acegisecurity.concurrent.ConcurrentLoginException=/login.jsp?login_error=too_many_user_error
???????
????
</
value
>
???????
</
property
>
</
bean
>
?
?
2
.
<
bean
id
=
"authenticationManager"
??????
class
=
"org.acegisecurity.providers.ProviderManager"
>
??????
<
property
name
=
"providers"
>
??????????
<
list
>
?????????????
<
ref
local
=
"daoAuthenticationProvider"
/>
?????????????
<
bean
class
=
"org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider"
>
?????????????????
<
property
name
=
"key"
value
=
"javajohnKey"
/>
?????????????
</
bean
>
?????????????
<
bean
class
=
"org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider"
>
?????????????????
<
property
name
=
"key"
value
=
"javajohnKey"
/>
?????????????
</
bean
>
??????????
</
list
>
??????
</
property
>
??
???
</
bean
>
?
3
.
<
bean
id
=
"daoAuthenticationProvider"
class
=
"org.acegisecurity.providers.dao.DaoAuthenticationProvider"
>
??????
<
property
name
=
"userDetailsService"
ref
=
"jdbcDaoImpl"
/>
??????
<
property
name
=
"userCache"
>
??????????
<
bean
class
=
"org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"
>
?????????????
<
property
name
=
"cache"
>
?????????????????
<
bean
class
=
"org.springframework.cache.ehcache.EhCacheFactoryBean"
>
????????????????????
<
property
name
=
"cacheManager"
>
????????????????????????
<
bean
class
=
"org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
/>
????????????????????
</
property
>
????????????????????
<
property
name
=
"cacheName"
value
=
"userCache"
/>
?????????????????
</
bean
>
?????????????
</
property
>
??????????
</
bean
>
??????
</
property
>
??????
<
property
name
=
"passwordEncoder"
ref
=
"passwordEncoder"
/>
???
</
bean
>
?
?
4
.
<
bean
id
=
"jdbcDaoImpl"
?????????
class
=
"org.acegisecurity.userdetails.jdbc.JdbcDaoImpl"
>
???????
<
property
name
=
"dataSource"
ref
=
"dataSource"
/>
???????
<
property
name
=
"usersByUsernameQuery"
>
???????????
<
value
>
??????????????? select loginid,passwd,1 from users where status='1' and loginid = ?
???????????
</
value
>
???????
</
property
>
???????
<
property
name
=
"authoritiesByUsernameQuery"
>
???????????
<
value
>
??????????????? select u.loginid,p.name from
??????????????? users u,roles r,permissions p,user_role ur,role_permis rp
??????????????? where
??????????????? u.id=ur.user_id and
??????????????? r.id=ur.role_id and
??????????????? p.id=rp.permis_id and
??????????????? r.id=rp.role_id and
??????????????? p.status='1' and u.loginid=?
???????????
</
value
>
???????
</
property
>
</
bean
>
?
?
二、程序流程:
1
.登錄的時(shí)候執(zhí)行的過(guò)濾為
authenticationProcessingFilter
,查看其實(shí)現(xiàn)為
org.bookStore.test.plugins.security.UserAuthenticationProcessingFilter
,該類(lèi)繼承自
org.acegisecurity.ui.webapp.AuthenticationProcessingFilter
,又繼承自
org.acegisecurity.ui.AbstractProcessingFilter
,這時(shí)候看到了
doFilter()
該方法取了
web
層傳過(guò)來(lái)的
request
和
response
,然后對(duì)登錄路徑執(zhí)行了判斷等操作,接下來(lái)執(zhí)行至
authResult = attemptAuthentication(httpRequest);
2
.從類(lèi)繼承關(guān)系上找到該方法的實(shí)現(xiàn)來(lái)自
AuthenticationProcessingFilter
,執(zhí)行的邏輯為先取出
web
層傳過(guò)來(lái)的用戶(hù)名和密碼接著將得到的信息包裝為
UsernamePasswordAuthenticationToken
:
public
UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
???
super
(
null
);
???
this
.
principal
= principal;????
???
this
.
credentials
= credentials;
??? setAuthenticated(
false
);
}
3
.接下來(lái)執(zhí)行了
setDetails(request, authRequest);
將
request
實(shí)例賦給
authRequest
的屬性。
4
.調(diào)用
authenticationManager
的
authenticate(authRequest)
方法。
5
.程序轉(zhuǎn)至
authenticationManager
內(nèi)執(zhí)行。該類(lèi)繼承自
org.acegisecurity. AbstractAuthenticationManager
,執(zhí)行方法
authenticate(authRequest)
:
public final Authentication authenticate(Authentication authRequest)
??? throws AuthenticationException {
??? try {
??????? Authentication authResult = doAuthentication(authRequest);
??????? copyDetails(authRequest, authResult);
?
??????? return authResult;
??? } catch (AuthenticationException e) {
??????? e.setAuthentication(authRequest);
??????? throw e;
??? }
}
doAuthentication(authRequest)
來(lái)自
ProviderManager
該方法執(zhí)行了其
providers
中的方法
authenticate(Authentication authentication)
6
.此方法中調(diào)用了
retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication)
該方法內(nèi)按
web
層用戶(hù)輸入的用戶(hù)名和密碼從數(shù)據(jù)庫(kù)內(nèi)比較是否有該用戶(hù),如果有則將其
user
表內(nèi)對(duì)應(yīng)的信息包裝為
UserDetail(
接口
,
實(shí)際為
User
的實(shí)例
)
的
List
對(duì)象,并將該用戶(hù)相應(yīng)的權(quán)限包裝為
GrantedAuthorityImpl
對(duì)象的
List
集合對(duì)象。至此程序返回至(
3.
)繼續(xù)執(zhí)行
7
.繼續(xù)執(zhí)行
org.acegisecurity.ui.AbstractProcessingFilter
的
successfulAuthentication(
HttpServletRequest request,
HttpServletResponse response,
Authentication authResult){
??? ......
SecurityContextHolder.getContext().setAuthentication(authResult);//
將包裝好的
UsernamePasswordAuthenticationToken
對(duì)象保存至系統(tǒng)上下文
......
}
8
.登錄執(zhí)行完畢。