`
san586
  • 浏览: 132496 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

Spring Security多登录口实现

阅读更多
ss3ex中配置的Spring Security一直是单登陆口,现改成多登录口,坚持少写代码的原则,但是不管怎么样,必须要解决以下几个问题:
1、用户未登录:访问权限页面,访问非权限页面
2、用户登录:访问权限页面(权限不够)
3、密码错误返回页面
4、注销页面
一个个问题来解决,第一个问题,用户未登录时访问访问非权限页面,直接就过了。麻烦的就是访问有权限的页面,因为Spring Security会使用AuthenticationEntryPoint在未登录用户访问被保护资源时自动跳转到登录页面,所以我们这里需要的就是扩展AuthenticaitonEntryPoint。
修改spring_security.xml文件:
<http auto-config="true" access-denied-page="/common/403.htm"
		entry-point-ref="loginPageEntryPoint">
		<intercept-url pattern="/login.**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
		<intercept-url pattern="/loginfont.**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
	……
<beans:bean id="loginPageEntryPoint" class="com.security.resource.LoginPageEntryPoint">
		<beans:property name="loginPageStrategy" ref="urlMappingLoginPageStrategy" />
	</beans:bean>
	<beans:bean id="urlMappingLoginPageStrategy"
		class="com.security.resource.UrlMappingLoginPageStrategy" />

LoginPageEntryPoint.java文件:
package com.security.resource;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.AuthenticationException;
import org.springframework.security.ui.AuthenticationEntryPoint;
import org.springframework.util.Assert;


public class LoginPageEntryPoint implements AuthenticationEntryPoint,
    InitializingBean {
    private LoginPageStrategy loginPageStrategy;

    public void afterPropertiesSet() throws Exception {
        Assert.notNull(loginPageStrategy,
            "loginPageStrategy must be specified");
    }

    public void commence(ServletRequest request, ServletResponse response,
        AuthenticationException authException)
        throws IOException, ServletException {
        loginPageStrategy.process((HttpServletRequest) request,
            (HttpServletResponse) response);
    }

    public void setLoginPageStrategy(LoginPageStrategy loginPageStrategy) {
        this.loginPageStrategy = loginPageStrategy;
    }
}
LoginPageStrategy.java 接口文件:
package com.security.resource;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public interface LoginPageStrategy {
    void process(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException;
}
UrlMappingLoginPageStrategy.java文件:
package com.security.resource;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class UrlMappingLoginPageStrategy implements LoginPageStrategy {
    public void process(HttpServletRequest request,
        HttpServletResponse response) throws IOException, ServletException {
        String targetUrl = null;
        String uri = request.getRequestURI();

        if (uri.indexOf("system") != -1) {
            targetUrl = "/login.jsp";
        } else {
            targetUrl = "/loginfont.jsp";
        }

        targetUrl = request.getContextPath() + targetUrl;
        response.sendRedirect(targetUrl);
    }
}
备注:别忘了在login.jsp同目录下复制一个jsp文件,取名叫loginfont.jsp。这2个文件代表着2个不同的登录口,表单提交的地址都是action="${base}/j_spring_security_check"。另外,因为多了一个登陆页面,他的权限也要放开,见上面修改的spring_security.xml文件。

第二个问题的解决方案有2个,分别是扩展AuthenticationProcessFilter,拦截403错误,还是根据url来判断跳转到不同的页面,这个方案我写了个类,开始抱着一定要实现的目的,由于逻辑上很多地方分散了,不好全部集中处理,后来觉得很麻烦,于是就放弃了。第二个方案相对来说,简单些,就是在用户登录时,往session中写进一个状态,如果不用session就用ThreadLocal,然后修改access-denied-page="/common/403.htm" 把这个页面改成一个action或者jsp的地址,在其中提取session中的值进行判断,跳转到不同的无权限错误页面。用户登录时写session有2个方案,一是,直接在ss3ex 中我配置的密码过滤器中操作(这个比较简单)。还有一个就是lingo介绍的自定义过滤器,他实现的步骤是:
添加spring_security.xml 文件
<!-- 自定义过滤器,刚开始由于没有配置authenticationFailureUrl属性,导致用户密码错误出错后,跳转页面不正常-->
	<beans:bean id="loginFilter" class="com.security.resource.LoginFilter">
<!-- 放置在AUTHENTICATION_PROCESSING_FILTER的前面-->
		<custom-filter before="AUTHENTICATION_PROCESSING_FILTER" />
<!-- 认证-->
		<beans:property name="authenticationManager" ref="authenticationManager" />
<!-- 认证错误页面-->
		<beans:property name="authenticationFailureUrl" value="/login.jsp?error=1" />  
<!-- 认证成功页面,必须的-->
		<beans:property name="defaultTargetUrl" value="/demo/success.shtml" />
	</beans:bean>
LoginFilter.java 文件:
package com.security.resource;

import javax.servlet.http.HttpServletRequest;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;

import com.utils.FakeSession;

public class LoginFilter extends AuthenticationProcessingFilter {

	public Authentication attemptAuthentication(HttpServletRequest request)
			throws AuthenticationException {
		Authentication authentication = super.attemptAuthentication(request);
		//状态, admin表示后台,font表示前台
		 String status = null;
	        String uri = request.getRequestURI();
	        if (uri.indexOf("system") != -1) {
	        	status = "admin";
	        } else {
	        	status = "font";
	        }
	        FakeSession.messageSegment.set(status);
		return authentication;
	}
}
FakeSession类(仿session)见我博客的另一篇文章。


第三个问题的解决方案,思路已经在第二个问题中解决了
<!-- 认证错误页面-->
		<beans:property name="authenticationFailureUrl" value="/login.jsp?error=1" />  

不过这里要修改下login.jsp,按照第二个问题的思路,写个判断的条件,根据ThreadLocal中status的状态跳转到不同的页面。

第四个问题的解决方案,注销页面,<logout logout-success-url="/login.jsp" invalidate-session="true" /> 也是修改这个页面,已经在第三个问题中解决了。

末:感谢狂人和lingo,提供的security的帮助,感谢小鸟提供的ThreadLocal。

老是有人问,再说详细点,补充如下(源代码在ss3ex中):
spring security2的流程
Spring Security会使用AuthenticationEntryPoint在未登录用户访问被保护资源时自动跳转到登录页面,自定义过滤器扩展AuthenticationProcessingFilter过滤器实现登录后,跳转页面前的后续操作,比如可以实现在跳转页面前往session中写入些内容。
Spring Security2多登录口实现
1、前后台登录页面;扩展AuthenticationEntryPoint过滤器
2、前后台认证成功页面;自定义过滤器扩展AuthenticationProcessingFilter过滤器
3、前后台认证失败页面;自定义过滤器扩展AuthenticationProcessingFilter过滤器
4、前后台无权限页面; access-denied-page
5、前后台注销返回页面。配置<logout logout-success-url="/login.jsp" invalidate-session="true" />标签
按照以上思路,可以实现无数个登录口。
分享到:
评论
2 楼 talangniao 2010-02-09  
String uri = request.getRequestURI(); 
获取到的都是/j_spring_security_check
这个能进行判断?返回哪个页面?
1 楼 talangniao 2010-02-09  
注销怎么返回不同的窗口?
发表评论

文章已被作者锁定,不允许评论。

相关推荐

Global site tag (gtag.js) - Google Analytics