最近公司做一项目要用到Spring Security3架构,所以搭了个测试环境,测试后发现登录认证没有走自定义的认证类,访问授权的没问题!希望各位高手多指点!!!下面是各部分代码!
      
一. web.xml部分
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>
            org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>二. applicationContext-security.xml
   
    <?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.0.xsd">

    <http auto-config="true" access-denied-page="/403.jsp"><!-- 当访问被拒绝时,会转到403.jsp -->
    
        <intercept-url pattern="/login.jsp" filters="none" />
        <form-login login-page="/login.jsp"
            authentication-failure-url="/login.jsp?error=true"
            default-target-url="/index.jsp" />
        <logout logout-success-url="/login.jsp" />
        <http-basic />
        
        <session-management>  
           <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" expired-url="/login.jsp"/>  
        </session-management>  
        
        <!-- 增加一个filter,这个filter位于FILTER_SECURITY_INTERCEPTOR之前 -->
        <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" />
    </http>
         <!-- 一个自定义的filter,必须包含authenticationManager,accessDecisionManager,securityMetadataSource三个属性,
    我们的所有控制将在这三个类中实现,解释详见具体配置 -->
    <beans:bean id="myFilter" class="com.zyht.pms.security.MyFilterSecurityInterceptor">
        <beans:property name="authenticationManager"  ref="authenticationManager" />
        <beans:property name="accessDecisionManager"  ref="myAccessDecisionManagerBean" />
        <beans:property name="securityMetadataSource"  ref="securityMetadataSource" />
    </beans:bean>
    
    <!-- 认证管理器,实现用户认证的入口,主要实现UserDetailsService接口即可 -->
    <authentication-manager alias="authenticationManager">
        <authentication-provider
            user-service-ref="myUserDetailService">
            <!-- 如果用户的密码采用加密的话,可以加点“盐”
                <password-encoder hash="md5" />-->
         </authentication-provider>
    </authentication-manager>
    
    <beans:bean id="myUserDetailService"
        class="com.zyht.pms.security.MyUserDetailService" />    <!-- 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 -->
    <beans:bean id="myAccessDecisionManagerBean"
        class="com.zyht.pms.security.MyAccessDecisionManager">
    </beans:bean>
    
    <!-- 资源源数据定义,即定义某一资源可以被哪些角色访问 -->
    <beans:bean id="securityMetadataSource"
        class="com.zyht.pms.security.MyInvocationSecurityMetadataSource" />
      
</beans:beans>三。 MyFilterSecurityInterceptor类
    
   public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter{ private FilterInvocationSecurityMetadataSource securityMetadataSource;    // ~ Methods
    // ========================================================================================================    /**
     * Method that is actually called by the filter chain. Simply delegates to
     * the {@link #invoke(FilterInvocation)} method.
     * 
     * @param request
     *            the servlet request
     * @param response
     *            the servlet response
     * @param chain
     *            the filter chain
     * 
     * @throws IOException
     *             if the filter chain fails
     * @throws ServletException
     *             if the filter chain fails
     */
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        FilterInvocation fi = new FilterInvocation(request, response, chain);
        invoke(fi);
    }    public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
        return this.securityMetadataSource;
    }    public Class<? extends Object> getSecureObjectClass() {
        return FilterInvocation.class;
    }    public void invoke(FilterInvocation fi) throws IOException,
            ServletException {
        InterceptorStatusToken token = super.beforeInvocation(fi);
        try {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } finally {
            super.afterInvocation(token, null);
        }
    }    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return this.securityMetadataSource;
    }    public void setSecurityMetadataSource(
            FilterInvocationSecurityMetadataSource newSource) {
        this.securityMetadataSource = newSource;
    }    public void destroy() {
    }    public void init(FilterConfig arg0) throws ServletException {
    }
}
四。myUserDetailService类    public class MyUserDetailService implements UserDetailsService { private UserDao userDao = null;

public void setUserDao(UserDao userDao) {
this.userDao = userDao;
} public UserDetails loadUserByUsername(String loginName)
throws UsernameNotFoundException, DataAccessException {
// TODO Auto-generated method stub

SjyUser loginUser = userDao.findUserByName(loginName);

if(null != loginUser){

Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();

String[] roles = loginUser.getRoles().split(",");

GrantedAuthorityImpl auth = null;
for(int i = 0; i < roles.length; i++){
auth = new GrantedAuthorityImpl(roles[i]);
auths.add(auth);
}

User user = new User(loginName,
loginUser.getPassword(), true, true, true, true, auths);
        return user;

}

return null;
}}
五。 MyAccessDecisionManager类    public class MyAccessDecisionManager implements AccessDecisionManager { public void decide(Authentication authentication, Object object,
Collection<ConfigAttribute> configAttributes) throws AccessDeniedException,
InsufficientAuthenticationException {
// TODO Auto-generated method stub

if(configAttributes == null){
          return ;
        }
                <!--由于登录没走认证类,所以这里修改为从session中获得用户信息-->
SjyUser user = (SjyUser)ServletActionContext.getRequest().getSession().getAttribute("loginUser");

        Iterator<ConfigAttribute>  ite = configAttributes.iterator();
        while(ite.hasNext()){
            ConfigAttribute ca=ite.next();
            String needRole=((SecurityConfig)ca).getAttribute();
            String[] roles = user.getRoles().split(",");
            for(int i = 0; i < roles.length; i++){
                if(needRole.equals(roles[i])){
                    return;
                }
            }
          <!--标准方式如下-->            /*for(GrantedAuthority ga:authentication.getAuthorities()){
                if(needRole.equals(ga.getAuthority())){  //ga is user's role.
                    return;
                }
            }*/
        }
        throw new AccessDeniedException("no right"); } public boolean supports(ConfigAttribute arg0) {
// TODO Auto-generated method stub
return true;
} public boolean supports(Class<?> arg0) {
// TODO Auto-generated method stub
return true;
}}
六。MyInvocationSecurityMetadataSource类    public class MyInvocationSecurityMetadataSource implements
FilterInvocationSecurityMetadataSource { private SysmenuDao sysmenuDao = null;
private UrlMatcher urlMatcher = new AntUrlPathMatcher();;
private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

public void setSysmenuDao(SysmenuDao sysmenuDao) {
this.sysmenuDao = sysmenuDao;
} public MyInvocationSecurityMetadataSource() {
}

public MyInvocationSecurityMetadataSource(SysmenuDao sysmenuDao) {
this.sysmenuDao = sysmenuDao;
loadResourceDefine();
} private void loadResourceDefine() {
List<SjySysmenu> sysmenus = sysmenuDao.selectSysmenuAll(); if (null != sysmenus && sysmenus.size() > 0) {
resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
Collection<ConfigAttribute> atts = null;

ConfigAttribute ca = null;
String[] roles = null;
for(SjySysmenu ss : sysmenus){

atts = new ArrayList<ConfigAttribute>();
roles = ss.getVisibleroles().split(",");

for(int i = 0; i < roles.length; i++){
ca = new SecurityConfig(roles[i]);
atts.add(ca);
}
resourceMap.put(ss.getLinkstr(), atts);
}
} } public Collection<ConfigAttribute> getAttributes(Object object)
throws IllegalArgumentException {
// TODO Auto-generated method stub

String url = ((FilterInvocation)object).getRequestUrl();
        Iterator<String> ite = resourceMap.keySet().iterator();
        while (ite.hasNext()) {
            String resURL = ite.next();
            if (urlMatcher.pathMatchesUrl(url, resURL)) {
                return resourceMap.get(resURL);
            }
        }
        return null;
} public boolean supports(Class<?> arg0) {
// TODO Auto-generated method stub
return true;
} public Collection<ConfigAttribute> getAllConfigAttributes() {
// TODO Auto-generated method stub
return null;
}
}
Spring Security3Springsecuritysecurity3

解决方案 »

  1.   

    七。action   public class userAction extends ActionSupport { private SjyUser user = null;
    private UserService userService = null; public SjyUser getUser() {
    return user;
    } public void setUser(SjyUser user) {
    this.user = user;
    }
    public void setUserService(UserService userService) {
    this.userService = userService;
    }
    @Override
    public String execute() throws Exception {
    SjyUser loginUser = userService.findUserByNameAndPassword(user.getLoginName(), user.getPassword());
    ServletActionContext.getRequest().getSession().setAttribute("loginUser", loginUser);
    if(null != loginUser){
    return this.SUCCESS;
    }
    return this.INPUT;
    }
    }
      

  2.   

    八。jsp <body>
        <s:form action="/userAction" method="post">
    <s:textfield name="user.loginName" label="用户名"></s:textfield>
    <s:textfield name="user.password" label="密码"></s:textfield>
    <s:submit value="登录"></s:submit>
    </s:form>
      </body>
      

  3.   

    对了,当登录的时候并不走myUserDetailService类!!!!!
      

  4.   

        <authentication-manager alias="authenticationManager">
            <authentication-provider  这里不用 ref = 'authProvider' 吗 //这个authProvider是你自定义的 
                user-service-ref="myUserDetailService"> 
                <!-- 如果用户的密码采用加密的话,可以加点“盐”
                    <password-encoder hash="md5" />-->
             </authentication-provider>
        </authentication-manager>其实你自己去拦截,还不如用它原有的类,继承一下就好了,
      

  5.   

    建议不要用自己写的FilterSecurityInterceptor实现类,除非你自己认为写的很完美才去重写一个,不然还是用默认的那个实现比较好,你可以参考下我博客里那些security文章,我个人比较喜欢用bean方式的,虽然是烦琐点,但是灵活性大大的增强,想怎么配置过滤链也可以