您的位置:首页 > 其它

acegi security实践教程—basic认证之debug调试

2014-02-23 21:10 483 查看
debug调试:

[align=left] 运行:http://localhost:8080/acegitest1/index.jsp[/align]
 因为web.xml中配置:

<filter-name >AcegiFilterChainProxy </filter-name >
<filter-class >
org.acegisecurity.util.FilterToBeanProxy
</filter-class >
<init-param >
<param-name >targetBean </param-name >
<param-value >filterChainProxy </param-value >
</init-param >
  
1. 进入:FilterToBeanProxy代理类中的doFilter,因为init只执行一次,启动时已经执行一次,所以访问url时,直接直接进入doFilter方法。
  
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (!initialized ) {
doInit();
}
delegate.doFilter(request, response, chain);
}

2. 进入:目标类filterChainProxy 中的doFilter
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);

ConfigAttributeDefinition cad = this.filterInvocationDefinitionSource .getAttributes(fi);

if (cad == null) {
if ( logger.isDebugEnabled()) {
logger.debug(fi.getRequestUrl() + " has no matching filters");
}
chain.doFilter(request, response);
return;
}
Filter[] filters = obtainAllDefinedFilters(cad);
if (filters.length == 0) {
if ( logger.isDebugEnabled()) {
logger.debug(fi.getRequestUrl() + " has an empty filter list");
}

chain.doFilter(request, response);
return;
}
VirtualFilterChain virtualFilterChain = new VirtualFilterChain(fi, filters);
virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse());
}


[align=left]   这个方法,主要获取aceg配置文件中,用户配置了多少个filter,并且filter顺序以数组形式展示,这样就开始filter过滤连了。[/align]
[align=left]3.进入:过滤连第一个filter,也就是咱们配置的basicProcessingFilter,其中doFilter如下:[/align]

 
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {

if (!(request instanceof HttpServletRequest)) {
throw new ServletException( "Can only process HttpServletRequest");
}

if (!(response instanceof HttpServletResponse)) {
throw new ServletException( "Can only process HttpServletResponse");
}

HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;

String header = httpRequest.getHeader( "Authorization");

if (logger.isDebugEnabled()) {
logger.debug( "Authorization header: " + header);
}

if ((header != null) && header.startsWith( "Basic ")) {
String base64Token = header.substring(6);
String token = new String(Base64.decodeBase64(base64Token.getBytes()));

String username = "";
String password = "";
int delim = token.indexOf( ":");

if (delim != -1) {
username = token.substring(0, delim);
password = token.substring(delim + 1);
}

if (authenticationIsRequired(username)) {
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken(username, password);
authRequest.setDetails(authenticationDetailsSource .buildDetails((HttpServletRequest) request));

Authentication authResult;

try {
authResult = authenticationManager.authenticate(authRequest);
} catch (AuthenticationException failed) {
// Authentication failed
if ( logger.isDebugEnabled()) {
logger.debug( "Authentication request for user: " + username + " failed: " + failed.toString());
}

SecurityContextHolder.getContext().setAuthentication( null);

if ( rememberMeServices != null) {
rememberMeServices.loginFail(httpRequest, httpResponse);
}

if ( ignoreFailure) {
chain.doFilter(request, response);
} else {
authenticationEntryPoint.commence(request, response, failed);
}

return;
}

// Authentication success
if ( logger.isDebugEnabled()) {
logger.debug( "Authentication success: " + authResult.toString());
}

SecurityContextHolder.getContext().setAuthentication(authResult);

if ( rememberMeServices != null) {
rememberMeServices.loginSuccess(httpRequest, httpResponse, authResult);
}
}
}

chain.doFilter(request, response);
}

   这个关键在于if ((header != null)
&& header.startsWith( "Basic ")),其中basic认证是把用户输入用户名和密码存放到header中,basic认证的。因为这个header为null【稍后在分析header】,所以执行下一个filter。

[align=left]4.进入exceptionfilter[/align]
[align=left]5.进入filterInvocationInterceptor[/align]

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}


    跟着进去invoke,然后进入InterceptorStatusToken token = super.beforeInvocation(fi);最后关键处在于ConfigAttributeDefinition
attr = this.obtainObjectDefinitionSource ().getAttributes(object);
[align=left]   obtainObjectDefinitionSource 大家眼熟吧,就是acegi配置文件,配置那个文件有那个角色。因为index.jsp没有配置,所以获取为null[/align]
[align=left]6.类似回调函数,一步步返回。这个页面就执行了一遍,即使exceptionfilter捕捉了异常,但是因为index.jsp没有配置授权的事情,所以异常filter中的异常策略authenticationEntryPoint没执行。[/align]
[align=left]  index.jsp访问完毕,我们来调试访问受保护的页面security.jsp,因为acegi进行配置了。上述已经把基本的流程跟大家调通,接下来就是不同之处,当然也是这个过滤连流程。因为访问受保护的资源,所以捕捉没有输入用户名和密码,然后异常交给basic处理,basic认证是弹出框,输入用户名和密码的。[/align]



[align=left]  那我们输入正确有效的用户,测试如下:[/align]
[align=left]  header如下:[/align]

  


 




你配置保护urlObjectDefinitionSource获取权限:
public ConfigAttributeDefinition lookupAttributes(String url) {
// Strip anything after a question mark symbol, as per SEC-161. See also SEC-321
int firstQuestionMarkIndex = url.indexOf( "?");

if (firstQuestionMarkIndex != -1) {
url = url.substring(0, firstQuestionMarkIndex);
}

if (isConvertUrlToLowercaseBeforeComparison()) {
url = url.toLowerCase();

if ( logger.isDebugEnabled()) {
logger.debug( "Converted URL to lowercase, from: '" + url + "'; to: '" + url + "'");
}
}

Iterator iter = requestMap.iterator();

while (iter.hasNext()) {
EntryHolder entryHolder = (EntryHolder) iter.next();

boolean matched = pathMatcher.match(entryHolder.getAntPath(), url);

if ( logger.isDebugEnabled()) {
logger.debug( "Candidate is: '" + url + "'; pattern is " + entryHolder.getAntPath() + "; matched="
+ matched);
}

if (matched) {
return entryHolder.getConfigAttributeDefinition();
}
}

return null;
}


[align=left]   进行投票机制:[/align]
[align=left]  关键代码:[/align]

authenticated = SecurityContextHolder.getContext().getAuthentication();
this. accessDecisionManager .decide(authenticated, object, attr);
public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
int result = ACCESS_ABSTAIN;
Iterator iter = config.getConfigAttributes();

while (iter.hasNext()) {
ConfigAttribute attribute = (ConfigAttribute) iter.next();

if ( this.supports(attribute)) {
result = ACCESS_DENIED;

// Attempt to find a matching granted authority
for ( int i = 0; i < authentication.getAuthorities().length ; i++) {
if (attribute.getAttribute().equals(authentication.getAuthorities()[i].getAuthority())) {
return ACCESS_GRANTED;
}
}
}
}

return result;
}
while (iter.hasNext()) {
AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();
int result = voter.vote(authentication, object, config);

switch (result) {
case AccessDecisionVoter. ACCESS_GRANTED:
return;

case AccessDecisionVoter. ACCESS_DENIED:
deny++;

break;

default:
break;
}
}

if (deny > 0) {
throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied" ,
"Access is denied"));
}


[align=left]      上述给的不是特别完整的代码,但是都是很关键的代码。大家可以下载源码,然后自己debug调试,同时我也会把acegi源码附上。[/align]
[align=left]      一般情况下完整的系统很少使用basic认证,因为每个系统都有自己的登陆页,若未登陆应该跳转到登陆页面,若权限不足,应该跳转到accessdefined页面。那我们下篇博客搭建基于表单认证。[/align]
       项目源码:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acegi basic认证 debug