spring security

spring security 提供系统安全功能

文章分类:Java编程

1.概述

     由于 spring security 是在权限系统开发关闭后补上去的所以只使用了 spring security 中的提供的一部分内容;

完成功能包括:用户校验、注销功能、Session 失效处理、防止一个用户同一时间内多次登录系统、保护系统资源(防止绕过登录访问资源)。

 

2.代码片段

 

Applicationcontext-security.xml代码 复制代码
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2.   
  3. <beans:beans xmlns="http://www.springframework.org/schema/security"  
  4.         xmlns:beans="http://www.springframework.org/schema/beans"  
  5.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  6.         xsi:schemaLocation="   
  7.             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
  8.             http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">   
  9.        
  10.     <!-- http安全配置 -->   
  11.     <http servlet-api-provision="true">   
  12.         <intercept-url pattern="/**/*.jpg" filters="none"/>   
  13.         <intercept-url pattern="/**/*.png" filters="none"/>   
  14.         <intercept-url pattern="/**/*.gif" filters="none"/>   
  15.         <intercept-url pattern="/**/*.css" filters="none"/>   
  16.         <intercept-url pattern="/**/*.js" filters="none"/>   
  17.            
  18.         <intercept-url pattern="/servlet/CheckLoginCodeServlet" filters="none"/>   
  19.         <intercept-url pattern="/servlet/SessionImage" filters="none"/>   
  20.         <intercept-url pattern="/login/login.jsp" filters="none"/>   
  21.         <intercept-url pattern="/login/logout.jsp" filters="none"/>   
  22.         <intercept-url pattern="/**" access="ROLE_ADMIN"/>   
  23.         <form-login login-page="/login/login.jsp"    
  24.             authentication-failure-url="/login/login.jsp"    
  25.             default-target-url="/login.do"  
  26.             always-use-default-target="true"/>   
  27.         <logout/>   
  28.         <concurrent-session-control/>   
  29.     </http>   
  30.        
  31.     <beans:bean id="jaasAuthenticationProvider"  
  32.         class="org.springframework.security.providers.jaas.JaasAuthenticationProvider">   
  33.         <custom-authentication-provider/>   
  34.         <beans:property name="loginConfig" value="/WEB-INF/login.conf" />   
  35.         <beans:property name="loginContextName" value="JAASTest" />   
  36.         <beans:property name="callbackHandlers">   
  37.             <beans:list>   
  38.                 <beans:bean class="org.springframework.security.providers.jaas.JaasNameCallbackHandler" />   
  39.                 <beans:bean class="org.springframework.security.providers.jaas.JaasPasswordCallbackHandler" />   
  40.             </beans:list>   
  41.         </beans:property>   
  42.         <beans:property name="authorityGranters">   
  43.             <beans:list>   
  44.                 <beans:bean class="com.hw.msds.login.businessimp.AuthorityGranterImpl" />   
  45.             </beans:list>   
  46.         </beans:property>   
  47.     </beans:bean>   
  48.   
  49.     <beans:bean id="sessionTimeoutFilter" class="com.hw.msds.login.businessimp.SessionTimeoutFilter">   
  50.         <custom-filter before="CONCURRENT_SESSION_FILTER" />   
  51.     </beans:bean>   
  52. </beans:beans>  
 
Login.jsp 片段代码 复制代码
  1. <form method="post" action="<%=basePath%>j_spring_security_check" onsubmit="return loginsubmit();">   
  2.   
  3.   
  4. 用户名: <input id="j_username" name="j_username" type="text"  class="user" />   
  5. 密&nbsp;&nbsp;码:<input id="j_password" name="j_password" type="password"  class="user" />   
  6.   
  7. <input id="submitbtn" type="submit" value="登 录" class="btn_login"/>   
  8.   
  9. </form>  
 
Logout.jsp代码 复制代码
  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>   
  2. <%   
  3. String path = request.getContextPath();   
  4. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";   
  5. %>   
  6.   
  7. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">   
  8. <html>   
  9.   <head>   
  10.     <base href="<%=basePath%>">   
  11.        
  12.     <title>登出</title>   
  13.        
  14.     <meta http-equiv="pragma" content="no-cache">   
  15.     <meta http-equiv="cache-control" content="no-cache">   
  16.     <meta http-equiv="expires" content="0">       
  17.     <script type="text/javascript">   
  18.         function init() {   
  19.             window.top.location.target="_top";   
  20.             window.top.location.href="j_spring_security_logout";   
  21.         }   
  22.         window.onload=init;   
  23.     </script>   
  24.   </head>   
  25.      
  26.   <body>   
  27.     session失效请 <a href="j_spring_security_logout" target="_top">重新登录</a>   
  28.   </body>   
  29. </html>  
 
Login.conf代码 复制代码
  1. JAASTest {   
  2.     com.hw.msds.login.businessimp.LoginModuleImpl required   
  3.     driver="oracle.jdbc.driver.OracleDriver"  
  4.     url="jdbc:oracle:thin:msds/msds@192.168.1.154:1521:msds"  
  5.     db_username="msds"  
  6.     db_password="msds"  
  7.     debug="true";   
  8. };  
 
Authoritygranterimpl.java代码 复制代码
  1. import java.security.Principal;   
  2. import java.util.HashSet;   
  3. import java.util.Set;   
  4. import org.springframework.security.providers.jaas.AuthorityGranter;   
  5.   
  6. public class AuthorityGranterImpl implements AuthorityGranter {   
  7.     public Set grant(Principal principal) {   
  8.         Set rtnSet = new HashSet();   
  9.         if (principal.getName().equals("TEST_PRINCIPAL")) {   
  10.             rtnSet.add("ROLE_ADMIN");   
  11.         }   
  12.         return rtnSet;   
  13.     }   
  14. }  
import java.security.Principal;
import java.util.HashSet;
import java.util.Set;
import org.springframework.security.providers.jaas.AuthorityGranter;

public class AuthorityGranterImpl implements AuthorityGranter {
    public Set grant(Principal principal) {
        Set rtnSet = new HashSet();
        if (principal.getName().equals("TEST_PRINCIPAL")) {
            rtnSet.add("ROLE_ADMIN");
        }
        return rtnSet;
    }
}
 
Loginmoduleimpl.java代码 复制代码
  1. import java.security.Principal;   
  2. import java.sql.Connection;   
  3. import java.sql.PreparedStatement;   
  4. import java.sql.ResultSet;   
  5. import java.sql.SQLException;   
  6. import java.util.Map;   
  7.   
  8. import javax.security.auth.Subject;   
  9. import javax.security.auth.callback.Callback;   
  10. import javax.security.auth.callback.CallbackHandler;   
  11. import javax.security.auth.callback.NameCallback;   
  12. import javax.security.auth.callback.PasswordCallback;   
  13. import javax.security.auth.callback.TextInputCallback;   
  14. import javax.security.auth.login.LoginException;   
  15. import javax.security.auth.spi.LoginModule;   
  16.   
  17. import org.springframework.security.context.SecurityContextHolder;   
  18.   
  19. import com.hw.msds.base.sys.Password;   
  20. import com.hw.msds.base.sys.SystemBuffer;   
  21. import com.hw.msds.base.util.DB;   
  22.   
  23. public class LoginModuleImpl implements LoginModule {   
  24.        
  25.     private Subject subject;   
  26.     private CallbackHandler callbackHandler;   
  27.     private Map sharedState;   
  28.     private Map options;   
  29.        
  30.     private String url;   
  31.     private String driver;   
  32.     private String db_username;   
  33.     private String db_password;   
  34.        
  35.     private String password;   
  36.     private String user;   
  37.        
  38.   
  39.     public boolean abort() throws LoginException {   
  40.         return true;   
  41.     }   
  42.   
  43.     public boolean commit() throws LoginException {   
  44.         return true;   
  45.     }   
  46.   
  47.     public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {   
  48.         this.subject = subject;   
  49.         this.callbackHandler = callbackHandler;   
  50.         this.sharedState = sharedState;   
  51.         this.options = options;   
  52.            
  53.         url = (String)options.get("url");   
  54.         driver = (String)options.get("driver");   
  55.         db_username = (String)options.get("db_username");   
  56.         db_password = (String)options.get("db_password");   
  57.   
  58.         try {   
  59.             TextInputCallback textCallback = new TextInputCallback("prompt");   
  60.             NameCallback nameCallback = new NameCallback("prompt");   
  61.             PasswordCallback passwordCallback = new PasswordCallback("prompt", false);   
  62.             callbackHandler.handle(new Callback[] {textCallback, nameCallback, passwordCallback});   
  63.                
  64.             password = new String(passwordCallback.getPassword());   
  65.             user = nameCallback.getName();   
  66.         } catch (Exception e) {   
  67.             throw new RuntimeException(e);   
  68.         }   
  69.     }   
  70.   
  71.     public boolean login() throws LoginException {   
  72.         System.out.println("driver " + driver);   
  73.         System.out.println("url " + url);   
  74.         System.out.println("db_username " + db_username);   
  75.         System.out.println("db_password " + db_password);   
  76.            
  77.         System.out.println("user " + user);   
  78.         System.out.println("password " + password);   
  79.            
  80.         String dpwd="";   
  81.         String dtype="";   
  82.         boolean flag=false;   
  83.            
  84.         // 校验用户   
  85.         String sql = "select tp.name, tps.secretcode, tc.type from tperson tp inner join tcorp tc on tp.corpid = tc.objid inner join tpersonpsw tps on tp.objid = tps.objid where tp.name = ?";   
  86.         Connection conn = DB.getConnection(driver, url, db_username, db_password);   
  87.         PreparedStatement stat = null;   
  88.         ResultSet rs = null;   
  89.         try {   
  90.             stat = conn.prepareStatement(sql);   
  91.             stat.setString(1, user);   
  92.             rs = stat.executeQuery();   
  93.                
  94.             while (rs != null && rs.next()) {   
  95.                 dpwd = rs.getString("secretcode");   
  96.                 dtype = rs.getString("type");   
  97.                 flag = true;   
  98.             }   
  99.         } catch (SQLException e) {   
  100.             e.printStackTrace();   
  101.         } finally {   
  102.             try {   
  103.                 if (rs != null) {   
  104.                     rs.close();   
  105.                 }   
  106.                 if (stat != null) {   
  107.                     stat.close();   
  108.                 }   
  109.             } catch (SQLException e) {   
  110.                 e.printStackTrace();   
  111.             }   
  112.         }   
  113.         DB.closeConnection(conn);   
  114.            
  115.         if (flag == false) {   
  116.             throw new LoginException("用户名不存在!");   
  117.         }   
  118.            
  119.         if (!dpwd.equals(Password.createPassword(password))) {   
  120.             throw new LoginException("密码错误!");   
  121.         }   
  122.         SystemBuffer.userInfo.put(user + "_password", dpwd);   
  123.         SystemBuffer.userInfo.put(user + "_logintype", dtype);   
  124.            
  125.            
  126.         subject.getPrincipals().add(new Principal() {   
  127.             public String getName() {   
  128.                 return "TEST_PRINCIPAL";   
  129.             }   
  130.         });   
  131.         return true;   
  132.     }   
  133.   
  134.     public boolean logout() throws LoginException {   
  135.         return true;   
  136.     }   
  137. }  
import java.security.Principal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;

import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.TextInputCallback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;

import org.springframework.security.context.SecurityContextHolder;

import com.hw.msds.base.sys.Password;
import com.hw.msds.base.sys.SystemBuffer;
import com.hw.msds.base.util.DB;

public class LoginModuleImpl implements LoginModule {
	
	private Subject subject;
	private CallbackHandler callbackHandler;
	private Map sharedState;
	private Map options;
	
	private String url;
	private String driver;
	private String db_username;
	private String db_password;
	
    private String password;
    private String user;
    

    public boolean abort() throws LoginException {
        return true;
    }

    public boolean commit() throws LoginException {
        return true;
    }

    public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
        this.subject = subject;
        this.callbackHandler = callbackHandler;
        this.sharedState = sharedState;
        this.options = options;
        
        url = (String)options.get("url");
        driver = (String)options.get("driver");
        db_username = (String)options.get("db_username");
        db_password = (String)options.get("db_password");

        try {
            TextInputCallback textCallback = new TextInputCallback("prompt");
            NameCallback nameCallback = new NameCallback("prompt");
            PasswordCallback passwordCallback = new PasswordCallback("prompt", false);
            callbackHandler.handle(new Callback[] {textCallback, nameCallback, passwordCallback});
            
            password = new String(passwordCallback.getPassword());
            user = nameCallback.getName();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public boolean login() throws LoginException {
    	System.out.println("driver " + driver);
    	System.out.println("url " + url);
    	System.out.println("db_username " + db_username);
    	System.out.println("db_password " + db_password);
    	
    	System.out.println("user " + user);
    	System.out.println("password " + password);
    	
    	String dpwd="";
    	String dtype="";
    	boolean flag=false;
    	
    	// 校验用户
    	String sql = "select tp.name, tps.secretcode, tc.type from tperson tp inner join tcorp tc on tp.corpid = tc.objid inner join tpersonpsw tps on tp.objid = tps.objid where tp.name = ?";
    	Connection conn = DB.getConnection(driver, url, db_username, db_password);
    	PreparedStatement stat = null;
		ResultSet rs = null;
		try {
			stat = conn.prepareStatement(sql);
			stat.setString(1, user);
			rs = stat.executeQuery();
			
			while (rs != null && rs.next()) {
				dpwd = rs.getString("secretcode");
				dtype = rs.getString("type");
				flag = true;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (rs != null) {
					rs.close();
				}
				if (stat != null) {
					stat.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
    	DB.closeConnection(conn);
    	
		if (flag == false) {
			throw new LoginException("用户名不存在!");
		}
		
		if (!dpwd.equals(Password.createPassword(password))) {
			throw new LoginException("密码错误!");
		}
		SystemBuffer.userInfo.put(user + "_password", dpwd);
		SystemBuffer.userInfo.put(user + "_logintype", dtype);
		
		
		subject.getPrincipals().add(new Principal() {
			public String getName() {
				return "TEST_PRINCIPAL";
			}
		});
		return true;
    }

    public boolean logout() throws LoginException {
        return true;
    }
}
 
Sessiontimeoutfilter.java代码 复制代码
  1. import java.io.IOException;   
  2.   
  3. import javax.servlet.FilterChain;   
  4. import javax.servlet.ServletException;   
  5. import javax.servlet.http.HttpServletRequest;   
  6. import javax.servlet.http.HttpServletResponse;   
  7. import javax.servlet.http.HttpSession;   
  8.   
  9. import org.springframework.security.ui.AbstractProcessingFilter;   
  10. import org.springframework.security.ui.SpringSecurityFilter;   
  11. import org.springframework.security.ui.savedrequest.SavedRequest;   
  12. import org.springframework.security.util.PortResolver;   
  13. import org.springframework.security.util.PortResolverImpl;   
  14.   
  15. public class SessionTimeoutFilter extends SpringSecurityFilter {   
  16.     private PortResolver portResolver = new PortResolverImpl();   
  17.     private String sessionTimeoutUrl;   
  18.   
  19.     public void doFilterHttp(HttpServletRequest request,   
  20.         HttpServletResponse response, FilterChain chain)   
  21.         throws IOException, ServletException {   
  22.         if (this.isSessionExpired(request)) {   
  23.             System.out.println("!!!!!!!!!!!!!!!!!!!!!!!! session过期");   
  24.             this.processRequest(request, response);   
  25.         } else {   
  26.             chain.doFilter(request, response);   
  27.         }   
  28.     }   
  29.   
  30.     protected String determineSessionTimeoutUrl(HttpServletRequest request) {   
  31.         return (sessionTimeoutUrl != null) ? sessionTimeoutUrl  : "/login/logout.jsp";   
  32.     }   
  33.   
  34.     protected boolean isSessionExpired(HttpServletRequest request) {   
  35.         return (request.getRequestedSessionId() != null)   
  36.         && !request.isRequestedSessionIdValid();   
  37.     }   
  38.   
  39.     protected void processRequest(HttpServletRequest request,   
  40.         HttpServletResponse response) throws IOException {   
  41.         HttpSession session = request.getSession();   
  42.         SavedRequest savedRequest = new SavedRequest(request, portResolver);   
  43.         session.setAttribute(AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY, new RuntimeException("连接超时,如果需要继续操作请重新登录系统!"));   
  44.         session.setAttribute(AbstractProcessingFilter.SPRING_SECURITY_SAVED_REQUEST_KEY, savedRequest);   
  45.         String targetUrl = determineSessionTimeoutUrl(request);   
  46.            
  47.         targetUrl = request.getContextPath() + targetUrl;   
  48.         response.sendRedirect(response.encodeRedirectURL(targetUrl));   
  49.     }   
  50.   
  51.     public int getOrder() {   
  52.         return 0;   
  53.     }   
  54. }  
import java.io.IOException;

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

import org.springframework.security.ui.AbstractProcessingFilter;
import org.springframework.security.ui.SpringSecurityFilter;
import org.springframework.security.ui.savedrequest.SavedRequest;
import org.springframework.security.util.PortResolver;
import org.springframework.security.util.PortResolverImpl;

public class SessionTimeoutFilter extends SpringSecurityFilter {
    private PortResolver portResolver = new PortResolverImpl();
    private String sessionTimeoutUrl;

    public void doFilterHttp(HttpServletRequest request,
        HttpServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        if (this.isSessionExpired(request)) {
        	System.out.println("!!!!!!!!!!!!!!!!!!!!!!!! session过期");
            this.processRequest(request, response);
        } else {
            chain.doFilter(request, response);
        }
    }

    protected String determineSessionTimeoutUrl(HttpServletRequest request) {
        return (sessionTimeoutUrl != null) ? sessionTimeoutUrl  : "/login/logout.jsp";
    }

    protected boolean isSessionExpired(HttpServletRequest request) {
        return (request.getRequestedSessionId() != null)
        && !request.isRequestedSessionIdValid();
    }

    protected void processRequest(HttpServletRequest request,
        HttpServletResponse response) throws IOException {
        HttpSession session = request.getSession();
        SavedRequest savedRequest = new SavedRequest(request, portResolver);
        session.setAttribute(AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY, new RuntimeException("连接超时,如果需要继续操作请重新登录系统!"));
        session.setAttribute(AbstractProcessingFilter.SPRING_SECURITY_SAVED_REQUEST_KEY, savedRequest);
        String targetUrl = determineSessionTimeoutUrl(request);
        
        targetUrl = request.getContextPath() + targetUrl;
        response.sendRedirect(response.encodeRedirectURL(targetUrl));
    }

	public int getOrder() {
		return 0;
	}
}

 3.说明

a. 用户校验和用户信息加载

     我是用了JAAS进行用户名密码校验,所有校验成功的用户都被分配了ROLE_ADMIN角色,校验失败抛出异常。

     校验成功后我指定了程序跳转至login.do,login.do作用就是加载用户相关信息(包括用户所属部门、所属公司、可操作的模块以及对应的权限信息)

b. 系统注销

     login.do 判断如果是注销,清空当前用户session,并转向 j_spring_security_logout 。

c. Session 失效处理

     详见 SessionTimeoutFilter.java ,   判断是否有 sessionid 存在如果存在判断是否过期,如果过期则调整至登录页面并给出提示信息,如果没有sessionid说明用户未登录过不错任何处理。

d. 防止一个用户同一时间内多次登录系统

     spring security 提供的功能    详见<concurrent-session-control/>

e. 保护系统资源(防止绕过登录访问资源)

     详见 <http> 部分, 注意当用户身份校验成功后,就会被赋予ROLE_ADMIN角色,意味着这他就能够访问所有页面(给个用户访问权限内的所有页面)

 

4.标注

     上面是我在最近项目中web安全方面的的一点点经验,希望大家多提建议。

 

参考文献:

spring security 安全开发手册

http://www.family168.com/oa/springsecurity/html/index.html

阅读更多
上一篇spring security
下一篇tomcat ,apache 负载均衡配置
想对作者说点什么? 我来说一句

spring-security-3.1.0.RC3

2011年12月05日 15.25MB 下载

springstarter

2009年12月18日 14.17MB 下载

Spring Security 资料合集

2015年01月24日 4.94MB 下载

spring security demo

2017年11月12日 358KB 下载

spring security acl 实例

2017年12月01日 28.3MB 下载

spring security demo2

2017年11月30日 28.95MB 下载

spring security spring security

2009年10月12日 237KB 下载

没有更多推荐了,返回首页

关闭
关闭