Spring Security3 + S2SH认证问题!!!!
最近公司做一项目要用到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 Security3 Spring security security3 --------------------编程问答-------------------- 七。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;
}
}
--------------------编程问答-------------------- 八。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> --------------------编程问答-------------------- 对了,当登录的时候并不走myUserDetailService类!!!!! --------------------编程问答-------------------- <authentication-manager alias="authenticationManager">
<authentication-provider 这里不用 ref = 'authProvider' 吗 //这个authProvider是你自定义的
user-service-ref="myUserDetailService">
<!-- 如果用户的密码采用加密的话,可以加点“盐”
<password-encoder hash="md5" />-->
</authentication-provider>
</authentication-manager>
其实你自己去拦截,还不如用它原有的类,继承一下就好了,
--------------------编程问答-------------------- 建议不要用自己写的FilterSecurityInterceptor实现类,除非你自己认为写的很完美才去重写一个,不然还是用默认的那个实现比较好,你可以参考下我博客里那些security文章,我个人比较喜欢用bean方式的,虽然是烦琐点,但是灵活性大大的增强,想怎么配置过滤链也可以
补充:Java , Web 开发