spring security

来源:互联网 发布:淘宝客自建网站引流 编辑:程序博客网 时间:2024/05/13 05:40

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. }  
 
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. }  
 
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. }  

 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

原创粉丝点击