Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个资源来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

不多说了,直接上代码,这里采用springmvc与springSecurity结合。

web.xml配置

web.xml中主要配置了springmvc与springSecurity,指定了配置文件applicationContext*.xml与applicationContext-servlet.xml

     
     
    
org.springframework.web.context.ContextLoaderListener
   
      
    
contextConfigLocation
    
/WEB-INF/applicationContext*.xml
  
    
  
    
springmvc
    
org.springframework.web.servlet.DispatcherServlet
    
      
contextConfigLocation
      
/WEB-INF/applicationContext-servlet.xml
    
    
1
  
  
    
springmvc
    
/
  
    
  
          
Set Character Encoding
          
org.springframework.web.filter.CharacterEncodingFilter
          
              
encoding
              
UTF-8
          
          
              
forceEncoding
              
true
          
      
        
          
Set Character Encoding
          
/*
      
              
  
    
springSecurityFilterChain
      
org.springframework.web.filter.DelegatingFilterProxy
  
  
    
springSecurityFilterChain
    
/*
  
  

springmvc的配置  applicationContext-servlet.xml

    
    
     
 
 
 

数据库连接配置 applicationContext.xml

    
             
         
             
         
        
        
        
        
        
        
        
        
        
        
        
        
        
        
   
 
  
  

上述配置中,需要用到config.properties相关连接信息

jdbc.driverClassName=com.mysql.jdbc.Driverjdbc.jdbcUrl=jdbc:mysql://localhost:3306/myhome?useUnicode=true&characterEncoding=utf-8jdbc.user=rootjdbc.password=123jdbc.minPoolSize=10jdbc.maxPoolSize=20jdbc.maxIdleTime=60jdbc.acquireIncrement=2jdbc.maxStatements=0jdbc.initialPoolSize=2jdbc.idleConnectionTestPeriod=60jdbc.acquireRetryAttempts=30jdbc.breakAfterAcquireFailure=falsejdbc.testConnectionOnCheckout=false

下面就开始重中之重了springSecurity的配置applicationContext-security.xml

   
         
         
       
       
       
       
         
        
                    
    
          
     
          
  
          
   
            
       
             
      
                
     
    
      
        
           

自定义filter拦截器FilterSecurityInterceptor,该方法需要继承AbstractSecurityInterceptor,其中最主要的是doFilter方法。

package com.xj.security;import java.io.IOException;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import org.springframework.security.access.SecurityMetadataSource;import org.springframework.security.access.intercept.AbstractSecurityInterceptor;import org.springframework.security.access.intercept.InterceptorStatusToken;import org.springframework.security.web.FilterInvocation;import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;//自定义过滤器public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter{   		//安全元数据资源	private MySecurityMetadataSource securityMetadataSource; 		@Override	public void destroy() {			}    	@Override	public void init(FilterConfig arg0) throws ServletException {			}		//可以这里进行相关操作	@Override	public void doFilter(ServletRequest request, ServletResponse response,			FilterChain chain) throws IOException, ServletException {		FilterInvocation fileInvocation  = new FilterInvocation(request, response, chain);		InterceptorStatusToken interceptorStatusToken = this.beforeInvocation(fileInvocation);  //校验访问的路径需要的角色等		fileInvocation.getChain().doFilter(request, response);		this.afterInvocation(interceptorStatusToken, null); 	}	@Override	public Class
 getSecureObjectClass() { return FilterInvocation.class; } @Override public SecurityMetadataSource obtainSecurityMetadataSource() { return this.securityMetadataSource; } public MySecurityMetadataSource getSecurityMetadataSource() { return securityMetadataSource; } public void setSecurityMetadataSource( MySecurityMetadataSource securityMetadataSource) { this.securityMetadataSource = securityMetadataSource; this.securityMetadataSource.refreshResource(); } }

由FilterSecurityInterceptor的配置可以看出,其需要认证管理器authenticationManager,决策管理器accessDecisionManager,资源管理器securityMetadataSource

认证管理器authenticationManager中,最主要的是UserDetailsService,该方法将用户的权限信息封装一个User放到spring的全局缓存SecurityContextHolder中,以备后面访问资源时使用

package com.xj.security;import java.util.ArrayList;import java.util.List;import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.authentication.DisabledException;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.GrantedAuthorityImpl;import org.springframework.security.core.userdetails.User;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.core.userdetails.UsernameNotFoundException;import com.xj.dao.CommonDao;//身份认证管理器public class MyUserDetailService implements UserDetailsService{    	@Autowired	private CommonDao commonDao;		@Override	public UserDetails loadUserByUsername(String username)throws UsernameNotFoundException {		List
 grantedAuthorities = new ArrayList
(); GrantedAuthority ga = null; String sql="select * from auth_user where username=?"; Map userMap = commonDao.queryForOne(sql, username); if(userMap==null||userMap.size()==0){ throw new UsernameNotFoundException("用户" + username + " 不存在"); } if(userMap.get("enabled").toString().equals("false")){ throw new DisabledException("用户" + username + " 被冻结"); } String password = userMap.get("password").toString(); String roleIds[] = ( (String)userMap.get("roleId")).split(","); sql = "select * from auth_role where id=?"; for(String roleId:roleIds){ Map roleMap = commonDao.queryForOne(sql, roleId); String rolename = (String)roleMap.get("rolename"); ga = new GrantedAuthorityImpl(rolename); grantedAuthorities.add(ga); } User user = new User(username, password, true, true, true, true, grantedAuthorities); return user; }   }

资源管理器,需要继承FilterInvocationSecurityMetadataSource服务器启动时,即加载数据库的资源信息

package com.xj.security;import java.util.ArrayList;import java.util.Collection;import java.util.HashMap;import java.util.List;import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.access.ConfigAttribute;import org.springframework.security.access.SecurityConfig;import org.springframework.security.web.FilterInvocation;import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;import com.xj.dao.CommonDao;//资源管理器(统计出要访问的资源需要的角色)public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource{	@Autowired	private CommonDao commonDao;	private Map
> resourceMap=null; //从数据库加载资源    public Map loadSource(){  resourceMap = new HashMap
>(); String resource_sql="select * from auth_resource"; String role_sql="select * from auth_role"; List
 resources = commonDao.queryForList(resource_sql); List roles = commonDao.queryForList(role_sql); Map
 roleMap = new HashMap
();  //对应了role表的map for(Map role:roles){ String id = role.get("id").toString(); String rolename = (String)role.get("rolename"); roleMap.put(id, rolename); } for(Map resource:resources){ Collection
 collection=new ArrayList
(); String url_pattern = (String)resource.get("url_pattern"); String access_role = (String)resource.get("access_role"); String roleIds[] = access_role.split(","); for(String roleId:roleIds){ ConfigAttribute ca = new SecurityConfig(roleMap.get(roleId)); collection.add(ca); } resourceMap.put(url_pattern, collection); } return resourceMap; } @Override public Collection
 getAllConfigAttributes() { return null; }     //获取访问某一个url所需的角色 @Override public Collection
 getAttributes(Object arg0) throws IllegalArgumentException { String url =((FilterInvocation)arg0).getRequestUrl(); if(resourceMap==null){ System.out.println("无访问权限"); return null; } Collection
 collection = resourceMap.get(url); return collection; } @Override public boolean supports(Class
 arg0) { return true; } /**  * 刷新资源配置  */ public void refreshResource(){ loadSource(); }}

需要commonDao类,可以算是一个公共类了

package com.xj.dao;import javax.sql.DataSource;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.sql.SQLException;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Properties;import java.util.Set;import java.util.Map.Entry;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.PreparedStatementSetter;import org.springframework.jdbc.core.RowMapper;import org.springframework.security.core.context.SecurityContextHolder;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.stereotype.Repository;import com.xj.util.Logger;import com.xj.util.PageInfo;@Repository("commonDao")public class CommonDao {	@Autowired	DataSource dataSource;	public int execUp(String sql, final String params[])			throws SQLException {				JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);		return jdbcTemplate.update(sql, new PreparedStatementSetter() {			public void setValues(PreparedStatement ps) throws SQLException {				if (params != null) {					for (int i = 0; i < params.length; i++) {						ps.setString(i + 1, params[i]);					}				}			}		});	}		public List
 execSql(String sql, final String params[]) { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); return jdbcTemplate.query(sql, new PreparedStatementSetter() { public void setValues(PreparedStatement ps) throws SQLException { if (params != null) { for (int i = 0; i < params.length; i++) { ps.setString(i + 1, params[i]); } } } }, new ItemMapper()); } protected class ItemMapper implements RowMapper { public Object mapRow(ResultSet rs, int rowNum) throws SQLException { Properties item = new Properties(); ResultSetMetaData rsmd = rs.getMetaData(); int len = rsmd.getColumnCount(); for (int i = 0; i < len; i = i + 1) { String colname = rsmd.getColumnName(i + 1); try { item.setProperty(colname, rs.getString(colname)); } catch (NullPointerException ex) { } } return item; } } public List queryForList(String sql, Object...objects) { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); System.out.println(sql); List list = jdbcTemplate.queryForList(sql,objects); return list; } public int queryForInt(String sql,Object...objects) { System.out.println(sql); JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); int result = jdbcTemplate.queryForInt(sql,objects); return result; } public int execute(String sql,Object...objects) { sql += ";"; String[] tempArray = sql.split("\\?"); String tempSql = tempArray[0]; for(int i=0;i
> list = jdbcTemplate.queryForList(sql,objects); if(list.size()!=0){ return list.get(0); }else{ return map; } } /**  * 插入Map 数据,key对应字段名,value对应字段值  * @param map  * @param tableName  * @param replace  * @return  */ public int insertMap(Map
 map,String tableName,boolean replace){ int r = -1; int size = map.size(); String params[] = new String[size]; int index = 0; String insertkeySql = ""; String insertValueSql = ""; String comma = ""; Iterator
> it = map.entrySet().iterator(); while (it.hasNext()) { Entry
 entry = (Entry
) it.next(); String k = entry.getKey(); String v = entry.getValue(); insertkeySql += comma + "`" + k + "`"; insertValueSql += comma + " ? "; comma = ", "; params[index] = v; index++; } String method = replace ? "REPLACE" : "INSERT"; String sql = method + " INTO " + tableName + " (" + insertkeySql + " ) VALUES ( " + insertValueSql + " )"; try { r = this.execUp(sql, params); } catch (Exception e) { e.printStackTrace(); } return r; } /**  * 更新数据表  * @param setal 更新数据Map  * @param whereal 条件Map  * @param tablename 表名  * @return  */ public int updateTable(Map
 setal, Map
 whereal, String tablename) { int r = -1; int size = setal.size() + whereal.size(); String params[] = new String[size]; int kid = 0; String setsql = ""; String comma = ""; Iterator
> it = setal.entrySet().iterator(); while (it.hasNext()) { Entry
 entry = (Entry
) it.next(); String k = entry.getKey(); String v = entry.getValue(); setsql += comma + "`" + k + "`" + " = ? "; comma = ", "; params[kid] = v; kid++; } String where = ""; comma = ""; it = whereal.entrySet().iterator(); while (it.hasNext()) { if (where.equals("")) { where = " WHERE "; } Entry
 entry = (Entry
) it.next(); String k = entry.getKey(); String v = entry.getValue(); String[] kw = k.split("[\\s,]"); if (kw.length == 2) { where += comma + " `" + kw[0] + "`" + " " + kw[1] + " ? "; } else if (kw.length == 3) { where += kw[0] + " `" + kw[1] + "`" + " " + kw[2] + " ? "; } else { where += comma + " `" + kw[0] + "`" + " = ? "; } comma = " AND "; params[kid] = v; kid++; } String sql = "UPDATE " + tablename + " SET " + setsql + where; // System.out.println( sql ); try { r = this.execUp(sql, params); } catch (Exception e) { e.printStackTrace(); } return r; } /**  * 查询表  * @param columnNameSet  * @param whereMap  * @param orderBy  * @param page  * @param pageCount  * @param tableName  * @param onlyOne  * @return  */ public List
 selectTable(Set
 columnNameSet, Map
 whereMap, String orderBy, int page, int pageCount, String tableName, boolean onlyOne) { int size = 0; String params[] = null; if (whereMap != null && whereMap.size() > 0) { size = whereMap.size(); params = new String[size]; } int kid = 0; String keysql = ""; String comma = ""; if (columnNameSet != null && columnNameSet.size() != 0) { for (String s : columnNameSet) { if (s.indexOf("(") != -1) { keysql += comma + "" + s + ""; } else { keysql += comma + "`" + s + "`"; } comma = " , "; } } else { keysql = " * "; } String where = ""; comma = ""; if (whereMap != null && whereMap.size() > 0) { Iterator
> it = whereMap.entrySet().iterator(); while (it.hasNext()) { if (where.equals("")) { where = " WHERE "; } Entry
 entry = (Entry
) it.next(); String k = entry.getKey(); String v = entry.getValue(); String[] kw = k.split("[\\s,]"); if (kw.length == 2) { where += comma + " `" + kw[0] + "`" + " " + kw[1] + " ? "; } else if (kw.length == 3) { where += kw[0] + " `" + kw[1] + "`" + " " + kw[2] + " ? "; } else { where += comma + " `" + kw[0] + "`" + " = ? "; } comma = " AND "; params[kid] = v; kid++; } } String order = ""; if (orderBy.equals("") == false) { order = " ORDER BY " + orderBy; } String limit = ""; if (page > 0) { if (pageCount <= 0) { pageCount = 20; } int pageOffet = (page - 1) * pageCount; limit = " LIMIT " + pageOffet + "," + pageCount; } if (onlyOne == true) { limit = " LIMIT 1 "; } String sql = "SELECT " + keysql + " FROM " + tableName + where + order + limit; System.out.println(sql); List
 l = null; try { l = this.execSql(sql, params); } catch (Exception e) { e.printStackTrace(); } return l; } public Properties getItem(Map
 whereMap, String tableName) { Properties pp = null; try { List
 l = selectTable(null, whereMap, "", -1, 0, tableName,true); if (l != null && l.size() > 0) { pp = l.get(0); } } catch (Exception ex) { ex.printStackTrace(); } return pp; } public Properties getItemById(String id, String tableName) { String sql = "SELECT * FROM " + tableName+ " WHERE `id` = ? Limit 1"; List
 l = null; Properties pp = null; try { l = this.execSql(sql, new String[] { id }); if (l != null && l.size() > 0) { pp = l.get(0); } } catch (Exception ex) { ex.printStackTrace(); } return pp; } public Map getItemById(long userId, String tableName) { // TODO Auto-generated method stub String sql = "SELECT * FROM " + tableName+ " WHERE `id` = ? Limit 1"; List
 l = null; Properties pp = null; try { l = this.execSql(sql, new String[] { String.valueOf(userId) }); if (l != null && l.size() > 0) { pp = l.get(0); } } catch (Exception ex) { ex.printStackTrace(); } return pp; }}

决策管理器AccessDecisionManager,判断用户的角色是否拥有操作的权限

package com.xj.security;import java.util.Collection;import org.springframework.security.access.AccessDecisionManager;import org.springframework.security.access.ConfigAttribute;import org.springframework.security.access.SecurityConfig;import org.springframework.security.core.Authentication;import org.springframework.security.core.GrantedAuthority;//决策管理器public class MyAccessDecisionManager implements AccessDecisionManager{ //auth用户具有的权限,attributes访问该资源所需的角色权限		@Override	public void decide(Authentication auth, Object object,Collection
 attributes) {  for(ConfigAttribute ca:attributes){  //访问资源需要的权限  String needRole =  ((SecurityConfig)ca).getAttribute();  for(GrantedAuthority ga:auth.getAuthorities()){  //用户拥有的权限  String role = ga.getAuthority();  if(role.equals(needRole)){  return;  }  }  }   } @Override public boolean supports(ConfigAttribute arg0) { return true; } @Override public boolean supports(Class
 arg0) { return true; }   }

基本配置就这样子

controller

package com.xj.action;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.servlet.ModelAndView;import com.xj.dao.CommonDao;@Controllerpublic class HelloController {	    @Autowired	private CommonDao commonDao;	@RequestMapping(value="/hello/justtest")	public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception {		return new ModelAndView("/test");	}		@RequestMapping(value="/login")	public ModelAndView login(HttpServletRequest request,HttpServletResponse response) throws Exception {		return new ModelAndView("/login");	}		@RequestMapping(value="/main")	   public ModelAndView loginSuccess(HttpServletRequest request,HttpServletResponse response) throws Exception {	   return new ModelAndView("/main");   }}

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>   
Insert title here    
    
      
用户名或密码错误       
       
    
        
     
                        用户名:
                     密码:
  
        
记住我
                     
                   

main.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%  String path = request.getContextPath();  String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";  %> 
<%=basePath%>"/>   
Insert title here   this is main page   
继续前进   
退出

大概就这样子了。

整个项目网盘地址为: