Spring Security简单Demo
1.创建项目且引入相关的.jar文件
spring-security-acl-2.0.5.jar
spring-security-core-2.0.5.jar
spring-security-taglibs-2.0.5.jar
2.创建相应的实体类:用户、角色、资源
2.1用户类:User.java需要实现UserDetails接口,具体内容如下:
package com.zsw.entity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Transient;
import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Proxy;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.userdetails.UserDetails;
/**
* 用户类
* @author Administrator
*/
@Entity
@Proxy(lazy = false)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class User implements UserDetails {
private static final long serialVersionUID = 8026813053768023527L;
/**
* 编号ID
*/
@Id
@GeneratedValue
private Integer id;
private String name; //用户名
private String password; //密码
private boolean disabled; //是否关闭
/**
* 用户所有的角色
*/
@ManyToMany(targetEntity = Role. class, fetch = FetchType.EAGER)
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Role> roles;
@Transient
private Map< String, List<Resource>> roleResources;
/**
* The default constructor
*/
public User() {
}
/**
* 根据User返回这个User所拥有的权限列表
*/
public GrantedAuthority[] getAuthorities() {
List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>(roles.size());
for(Role role : roles) {
grantedAuthorities.add( new GrantedAuthorityImpl(role.getName()));
}
return grantedAuthorities.toArray( new GrantedAuthority[roles.size()]);
}
/**
* Returns the authorites string
*
* eg.
* downpour --- ROLE_ADMIN,ROLE_USER
* robbin --- ROLE_ADMIN
*
* @return
*/
public String getAuthoritiesString() {
List< String> authorities = new ArrayList< String>();
for(GrantedAuthority authority : this.getAuthorities()) {
authorities.add(authority.getAuthority());
}
return StringUtils.join(authorities, ",");
}
public String getPassword() {
return password;
}
public String getUsername() {
return name;
}
public boolean isAccountNonExpired() {
return true;
}
public boolean isAccountNonLocked() {
return true;
}
public boolean isCredentialsNonExpired() {
return true;
}
public boolean isEnabled() {
return !disabled;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public boolean isDisabled() {
return disabled;
}
public Set<Role> getRoles() {
return roles;
}
/**
* 在User对象中设置一个缓存机制,在第一次取的时候,
* 通过遍历User所有的Role,获取相应的Resource信息。
* @return
*/
public Map< String, List<Resource>> getRoleResources() {
// init roleResources for the first time
if( this.roleResources == null) {
this.roleResources = new HashMap< String, List<Resource>>();
for(Role role : this.roles) {
String roleName = role.getName();
Set<Resource> resources = role.getResources();
for(Resource resource : resources) {
String key = roleName + "_" + resource.getType();
if(! this.roleResources.containsKey(key)) {
this.roleResources.put(key, new ArrayList<Resource>());
}
this.roleResources.get(key).add(resource);
}
}
}
return this.roleResources;
}
public void setId(Integer id) {
this.id = id;
}
public void setName( String name) {
this.name = name;
}
public void setPassword( String password) {
this.password = password;
}
public void setDisabled( boolean disabled) {
this.disabled = disabled;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Transient;
import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Proxy;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.userdetails.UserDetails;
/**
* 用户类
* @author Administrator
*/
@Entity
@Proxy(lazy = false)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class User implements UserDetails {
private static final long serialVersionUID = 8026813053768023527L;
/**
* 编号ID
*/
@Id
@GeneratedValue
private Integer id;
private String name; //用户名
private String password; //密码
private boolean disabled; //是否关闭
/**
* 用户所有的角色
*/
@ManyToMany(targetEntity = Role. class, fetch = FetchType.EAGER)
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Role> roles;
@Transient
private Map< String, List<Resource>> roleResources;
/**
* The default constructor
*/
public User() {
}
/**
* 根据User返回这个User所拥有的权限列表
*/
public GrantedAuthority[] getAuthorities() {
List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>(roles.size());
for(Role role : roles) {
grantedAuthorities.add( new GrantedAuthorityImpl(role.getName()));
}
return grantedAuthorities.toArray( new GrantedAuthority[roles.size()]);
}
/**
* Returns the authorites string
*
* eg.
* downpour --- ROLE_ADMIN,ROLE_USER
* robbin --- ROLE_ADMIN
*
* @return
*/
public String getAuthoritiesString() {
List< String> authorities = new ArrayList< String>();
for(GrantedAuthority authority : this.getAuthorities()) {
authorities.add(authority.getAuthority());
}
return StringUtils.join(authorities, ",");
}
public String getPassword() {
return password;
}
public String getUsername() {
return name;
}
public boolean isAccountNonExpired() {
return true;
}
public boolean isAccountNonLocked() {
return true;
}
public boolean isCredentialsNonExpired() {
return true;
}
public boolean isEnabled() {
return !disabled;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public boolean isDisabled() {
return disabled;
}
public Set<Role> getRoles() {
return roles;
}
/**
* 在User对象中设置一个缓存机制,在第一次取的时候,
* 通过遍历User所有的Role,获取相应的Resource信息。
* @return
*/
public Map< String, List<Resource>> getRoleResources() {
// init roleResources for the first time
if( this.roleResources == null) {
this.roleResources = new HashMap< String, List<Resource>>();
for(Role role : this.roles) {
String roleName = role.getName();
Set<Resource> resources = role.getResources();
for(Resource resource : resources) {
String key = roleName + "_" + resource.getType();
if(! this.roleResources.containsKey(key)) {
this.roleResources.put(key, new ArrayList<Resource>());
}
this.roleResources.get(key).add(resource);
}
}
}
return this.roleResources;
}
public void setId(Integer id) {
this.id = id;
}
public void setName( String name) {
this.name = name;
}
public void setPassword( String password) {
this.password = password;
}
public void setDisabled( boolean disabled) {
this.disabled = disabled;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
其中,接口UserDetails定义的方法如下:
public
interface UserDetails
extends Serializable {
GrantedAuthority[] getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
GrantedAuthority[] getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
2.2角色:Role.java具体的内容如下:
package com.zsw.entity;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
/**
* 角色
* @author Administrator
*/
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Role {
@Id
@GeneratedValue
private Integer id;
private String name;
private String description;
@ManyToMany(targetEntity = Resource. class, fetch = FetchType.EAGER)
@JoinTable(name = "role_resource", joinColumns = @JoinColumn(name = "role_id"), inverseJoinColumns = @JoinColumn(name = "resource_id"))
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Resource> resources;
public Role() {
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public Set<Resource> getResources() {
return resources;
}
public void setId(Integer id) {
this.id = id;
}
public void setName( String name) {
this.name = name;
}
public void setDescription( String description) {
this.description = description;
}
public void setResources(Set<Resource> resources) {
this.resources = resources;
}
}
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
/**
* 角色
* @author Administrator
*/
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Role {
@Id
@GeneratedValue
private Integer id;
private String name;
private String description;
@ManyToMany(targetEntity = Resource. class, fetch = FetchType.EAGER)
@JoinTable(name = "role_resource", joinColumns = @JoinColumn(name = "role_id"), inverseJoinColumns = @JoinColumn(name = "resource_id"))
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Resource> resources;
public Role() {
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public Set<Resource> getResources() {
return resources;
}
public void setId(Integer id) {
this.id = id;
}
public void setName( String name) {
this.name = name;
}
public void setDescription( String description) {
this.description = description;
}
public void setResources(Set<Resource> resources) {
this.resources = resources;
}
}
2.3资源Resource.java具体的内容如下:
package com.zsw.entity;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Transient;
import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
/**
* 资源
* Resource可能分成多种类型,比如MENU,URL,METHOD等等
*/
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Resource {
@Id
@GeneratedValue
private Integer id;
private String type;
private String value;
@ManyToMany(mappedBy = "resources", targetEntity = Role. class, fetch = FetchType.EAGER)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Role> roles;
public Resource() {
}
/**
* 获取资源中所有角色名称
* @return
*/
@Transient
public String getRoleAuthorities() {
List< String> roleAuthorities = new ArrayList< String>();
for(Role role : roles) {
roleAuthorities.add(role.getName());
}
return StringUtils.join(roleAuthorities, ",");
}
public Integer getId() {
return id;
}
public String getType() {
return type;
}
public String getValue() {
return value;
}
public Set<Role> getRoles() {
return roles;
}
public void setId(Integer id) {
this.id = id;
}
public void setType( String type) {
this.type = type;
}
public void setValue( String value) {
this.value = value;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Transient;
import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
/**
* 资源
* Resource可能分成多种类型,比如MENU,URL,METHOD等等
*/
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Resource {
@Id
@GeneratedValue
private Integer id;
private String type;
private String value;
@ManyToMany(mappedBy = "resources", targetEntity = Role. class, fetch = FetchType.EAGER)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Role> roles;
public Resource() {
}
/**
* 获取资源中所有角色名称
* @return
*/
@Transient
public String getRoleAuthorities() {
List< String> roleAuthorities = new ArrayList< String>();
for(Role role : roles) {
roleAuthorities.add(role.getName());
}
return StringUtils.join(roleAuthorities, ",");
}
public Integer getId() {
return id;
}
public String getType() {
return type;
}
public String getValue() {
return value;
}
public Set<Role> getRoles() {
return roles;
}
public void setId(Integer id) {
this.id = id;
}
public void setType( String type) {
this.type = type;
}
public void setValue( String value) {
this.value = value;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
3.定义一个接口SecurityManager.java用于获取所有的资源信息
package com.zsw.security;
import java.util.Map;
/**
* 安全管理
* @author Administrator
*/
public interface SecurityManager {
public Map< String, String> loadUrlAuthorities();
}
import java.util.Map;
/**
* 安全管理
* @author Administrator
*/
public interface SecurityManager {
public Map< String, String> loadUrlAuthorities();
}
其具体的实现类如下:
package com.zsw.security.support;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.zsw.entity.Resource;
import com.zsw.entity.User;
import com.zsw.security.SecurityManager;
@Service( "securityManager")
public class SecurityManagerSupport extends HibernateDaoSupport implements UserDetailsService, SecurityManager {
@Autowired
public void init(SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
}
/**
* 根据用户名获取用户对象
* 实现了UserDetailsService接口中的loadUserByUsername方法
*/
public UserDetails loadUserByUsername( String userName) throws UsernameNotFoundException, DataAccessException {
List<User> users = getHibernateTemplate().find( "FROM User user WHERE user.name = ? AND user.disabled = false", userName);
if(users.isEmpty()) {
throw new UsernameNotFoundException( "User " + userName + " has no GrantedAuthority");
}
return users.get(0);
}
/**
* 获取所有资源,对应所有的角色
*/
public Map< String, String> loadUrlAuthorities() {
Map< String, String> urlAuthorities = new HashMap< String, String>();
List<Resource> urlResources = getHibernateTemplate().find( "FROM Resource resource WHERE resource.type = ?", "URL");
for(Resource resource : urlResources) {
urlAuthorities.put(resource.getValue(), resource.getRoleAuthorities());
}
return urlAuthorities;
}
}
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.zsw.entity.Resource;
import com.zsw.entity.User;
import com.zsw.security.SecurityManager;
@Service( "securityManager")
public class SecurityManagerSupport extends HibernateDaoSupport implements UserDetailsService, SecurityManager {
@Autowired
public void init(SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
}
/**
* 根据用户名获取用户对象
* 实现了UserDetailsService接口中的loadUserByUsername方法
*/
public UserDetails loadUserByUsername( String userName) throws UsernameNotFoundException, DataAccessException {
List<User> users = getHibernateTemplate().find( "FROM User user WHERE user.name = ? AND user.disabled = false", userName);
if(users.isEmpty()) {
throw new UsernameNotFoundException( "User " + userName + " has no GrantedAuthority");
}
return users.get(0);
}
/**
* 获取所有资源,对应所有的角色
*/
public Map< String, String> loadUrlAuthorities() {
Map< String, String> urlAuthorities = new HashMap< String, String>();
List<Resource> urlResources = getHibernateTemplate().find( "FROM Resource resource WHERE resource.type = ?", "URL");
for(Resource resource : urlResources) {
urlAuthorities.put(resource.getValue(), resource.getRoleAuthorities());
}
return urlAuthorities;
}
}
4.创建一个监听器,在系统启动的时候,把所有的资源load到内存作为缓存
package com.zsw.web.loader;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.zsw.security.SecurityManager;
/**
* ------------------------------------------------------------
* 这是一个监听器
* 主要有2个方法,一个是应用启动时执行,另一个是应用关闭时执行
* 在系统启动的时候,把所有的资源load到内存作为缓存
* ------------------------------------------------------------
* 监听器的使用实际上适用于取代那些响应用户请求的Servelt,
* 所以Listener类中无须提供用户请求的方法,
* Listener的作用是为整个WEB应用提供后台服务。
* ------------------------------------------------------------
* @author 周尚武
*/
public class ServletContextLoaderListener implements ServletContextListener {
/**
* 应用启动时,该方法调用
* 将资源的存放在servletContext中
*/
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
SecurityManager securityManager = this.getSecurityManager(servletContext);
Map< String, String> urlAuthorities = securityManager.loadUrlAuthorities();
servletContext.setAttribute( "urlAuthorities", urlAuthorities);
}
/**
* 应用关闭时该方法调用
*/
public void contextDestroyed(ServletContextEvent servletContextEvent) {
servletContextEvent.getServletContext().removeAttribute( "urlAuthorities");
}
protected SecurityManager getSecurityManager(ServletContext servletContext) {
return (SecurityManager) WebApplicationContextUtils.getWebApplicationContext(servletContext).getBean( "securityManager");
}
}
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.zsw.security.SecurityManager;
/**
* ------------------------------------------------------------
* 这是一个监听器
* 主要有2个方法,一个是应用启动时执行,另一个是应用关闭时执行
* 在系统启动的时候,把所有的资源load到内存作为缓存
* ------------------------------------------------------------
* 监听器的使用实际上适用于取代那些响应用户请求的Servelt,
* 所以Listener类中无须提供用户请求的方法,
* Listener的作用是为整个WEB应用提供后台服务。
* ------------------------------------------------------------
* @author 周尚武
*/
public class ServletContextLoaderListener implements ServletContextListener {
/**
* 应用启动时,该方法调用
* 将资源的存放在servletContext中
*/
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext servletContext = servletContextEvent.getServletContext();
SecurityManager securityManager = this.getSecurityManager(servletContext);
Map< String, String> urlAuthorities = securityManager.loadUrlAuthorities();
servletContext.setAttribute( "urlAuthorities", urlAuthorities);
}
/**
* 应用关闭时该方法调用
*/
public void contextDestroyed(ServletContextEvent servletContextEvent) {
servletContextEvent.getServletContext().removeAttribute( "urlAuthorities");
}
protected SecurityManager getSecurityManager(ServletContext servletContext) {
return (SecurityManager) WebApplicationContextUtils.getWebApplicationContext(servletContext).getBean( "securityManager");
}
}
5.获取当前用户
package com.zsw.security.support;
import org.springframework.security.context.SecurityContextHolder;
import com.zsw.entity.User;
/**
* Spring Security提供了一个线程安全的对象:SecurityContextHolder,
* 通过这个对象,我们可以访问当前的登录用户
* @author Administrator
*/
public class SecurityUserHolder {
/**
* 获取当前用户
* @return
*/
public static User getCurrentUser() {
return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
import org.springframework.security.context.SecurityContextHolder;
import com.zsw.entity.User;
/**
* Spring Security提供了一个线程安全的对象:SecurityContextHolder,
* 通过这个对象,我们可以访问当前的登录用户
* @author Administrator
*/
public class SecurityUserHolder {
/**
* 获取当前用户
* @return
*/
public static User getCurrentUser() {
return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
6.对资源进行认证
package com.zsw.security.interceptor;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.ConfigAttributeEditor;
import org.springframework.security.intercept.web.FilterInvocation;
import org.springframework.security.intercept.web.FilterInvocationDefinitionSource;
import org.springframework.security.util.AntUrlPathMatcher;
import org.springframework.security.util.RegexUrlPathMatcher;
import org.springframework.security.util.UrlMatcher;
/**
* 资源拦截器
* 编写自己的FilterInvocationDefinitionSource实现类,对资源进行认证
*/
public class SecureResourceFilterInvocationDefinitionSource implements FilterInvocationDefinitionSource, InitializingBean {
private UrlMatcher urlMatcher;
private boolean useAntPath = true;
private boolean lowercaseComparisons = true;
public void setUseAntPath( boolean useAntPath) {
this.useAntPath = useAntPath;
}
public void setLowercaseComparisons( boolean lowercaseComparisons) {
this.lowercaseComparisons = lowercaseComparisons;
}
public void afterPropertiesSet() throws Exception {
this.urlMatcher = new RegexUrlPathMatcher();
if (useAntPath) {
this.urlMatcher = new AntUrlPathMatcher();
}
if ( "true".equals(lowercaseComparisons)) {
if (! this.useAntPath) {
((RegexUrlPathMatcher) this.urlMatcher).setRequiresLowerCaseUrl(true);
}
} else if ( "false".equals(lowercaseComparisons)) {
if ( this.useAntPath) {
((AntUrlPathMatcher) this.urlMatcher).setRequiresLowerCaseUrl(false);
}
}
}
public ConfigAttributeDefinition getAttributes(Object filter) throws IllegalArgumentException {
FilterInvocation filterInvocation = (FilterInvocation) filter;
String requestURI = filterInvocation.getRequestUrl();
Map< String, String> urlAuthorities = this.getUrlAuthorities(filterInvocation);
String grantedAuthorities = null;
for(Iterator<Map.Entry< String, String>> iter = urlAuthorities.entrySet().iterator(); iter.hasNext();) {
Map.Entry< String, String> entry = iter.next();
String url = entry.getKey();
if(urlMatcher.pathMatchesUrl(url, requestURI)) {
grantedAuthorities = entry.getValue();
break;
}
}
if(grantedAuthorities != null) {
ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
configAttrEditor.setAsText(grantedAuthorities);
return (ConfigAttributeDefinition) configAttrEditor.getValue();
}
return null;
}
@SuppressWarnings( "unchecked")
public Collection getConfigAttributeDefinitions() {
return null;
}
@SuppressWarnings( "unchecked")
public boolean supports(Class clazz) {
return true;
}
@SuppressWarnings( "unchecked")
private Map< String, String> getUrlAuthorities(FilterInvocation filterInvocation) {
ServletContext servletContext = filterInvocation.getHttpRequest().getSession().getServletContext();
return (Map< String, String>)servletContext.getAttribute( "urlAuthorities");
}
}
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.ConfigAttributeEditor;
import org.springframework.security.intercept.web.FilterInvocation;
import org.springframework.security.intercept.web.FilterInvocationDefinitionSource;
import org.springframework.security.util.AntUrlPathMatcher;
import org.springframework.security.util.RegexUrlPathMatcher;
import org.springframework.security.util.UrlMatcher;
/**
* 资源拦截器
* 编写自己的FilterInvocationDefinitionSource实现类,对资源进行认证
*/
public class SecureResourceFilterInvocationDefinitionSource implements FilterInvocationDefinitionSource, InitializingBean {
private UrlMatcher urlMatcher;
private boolean useAntPath = true;
private boolean lowercaseComparisons = true;
public void setUseAntPath( boolean useAntPath) {
this.useAntPath = useAntPath;
}
public void setLowercaseComparisons( boolean lowercaseComparisons) {
this.lowercaseComparisons = lowercaseComparisons;
}
public void afterPropertiesSet() throws Exception {
this.urlMatcher = new RegexUrlPathMatcher();
if (useAntPath) {
this.urlMatcher = new AntUrlPathMatcher();
}
if ( "true".equals(lowercaseComparisons)) {
if (! this.useAntPath) {
((RegexUrlPathMatcher) this.urlMatcher).setRequiresLowerCaseUrl(true);
}
} else if ( "false".equals(lowercaseComparisons)) {
if ( this.useAntPath) {
((AntUrlPathMatcher) this.urlMatcher).setRequiresLowerCaseUrl(false);
}
}
}
public ConfigAttributeDefinition getAttributes(Object filter) throws IllegalArgumentException {
FilterInvocation filterInvocation = (FilterInvocation) filter;
String requestURI = filterInvocation.getRequestUrl();
Map< String, String> urlAuthorities = this.getUrlAuthorities(filterInvocation);
String grantedAuthorities = null;
for(Iterator<Map.Entry< String, String>> iter = urlAuthorities.entrySet().iterator(); iter.hasNext();) {
Map.Entry< String, String> entry = iter.next();
String url = entry.getKey();
if(urlMatcher.pathMatchesUrl(url, requestURI)) {
grantedAuthorities = entry.getValue();
break;
}
}
if(grantedAuthorities != null) {
ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
configAttrEditor.setAsText(grantedAuthorities);
return (ConfigAttributeDefinition) configAttrEditor.getValue();
}
return null;
}
@SuppressWarnings( "unchecked")
public Collection getConfigAttributeDefinitions() {
return null;
}
@SuppressWarnings( "unchecked")
public boolean supports(Class clazz) {
return true;
}
@SuppressWarnings( "unchecked")
private Map< String, String> getUrlAuthorities(FilterInvocation filterInvocation) {
ServletContext servletContext = filterInvocation.getHttpRequest().getSession().getServletContext();
return (Map< String, String>)servletContext.getAttribute( "urlAuthorities");
}
}
7.创建登陆login页面及登陆成功后的index页面:
login.jsp
<
%@ page language=
"java"
contentType=
"text/html; charset=UTF-8"
pageEncoding=
"UTF-8"
%>
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns= "http://www.w3.org/1999/xhtml" lang= "zh-CN" >
< head>
< title>Spring Security< /title>
< /head>
< body>
< form method= "post" id= "loginForm" action= "${pageContext.request.contextPath}/j_spring_security_check" >
< p>User Name:< /p>
< p>< input type= "text" name= "j_username" id= "j_username" />< /p>
< p>Password:< /p>
< p>< input type= "password" name= "j_password" id= "j_password" />< /p>
< p>< input type= "submit" value= "submit" />< /p>
< /form>
< /body>
< /html>
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns= "http://www.w3.org/1999/xhtml" lang= "zh-CN" >
< head>
< title>Spring Security< /title>
< /head>
< body>
< form method= "post" id= "loginForm" action= "${pageContext.request.contextPath}/j_spring_security_check" >
< p>User Name:< /p>
< p>< input type= "text" name= "j_username" id= "j_username" />< /p>
< p>Password:< /p>
< p>< input type= "password" name= "j_password" id= "j_password" />< /p>
< p>< input type= "submit" value= "submit" />< /p>
< /form>
< /body>
< /html>
index.jsp
<
p>
< a href= "${pageContext.request.contextPath}/j_spring_security_logout" >logout< /a>
< /p>
< p>Hello ${currentUser.name}, your role is: ${currentUser.authoritiesString}< /p>
< a href= "${pageContext.request.contextPath}/j_spring_security_logout" >logout< /a>
< /p>
< p>Hello ${currentUser.name}, your role is: ${currentUser.authoritiesString}< /p>
8.相关的配置文件:
8.1web.xml
<
?xml version=
"1.0"
encoding=
"UTF-8"
?>
< web-app id= "Yoda" version= "2.4" xmlns= "http://java.sun.com/xml/ns/j2ee"
xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation= "http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" >
< display-name>Yoda< /display-name>
<!--- Spring ApplicationContext Definition -->
< context-param>
< param-name>contextConfigLocation< /param-name>
< param-value>/WEB-INF/classes/applicationContext-*.xml< /param-value>
< /context-param>
<!---
Spring security Filter
这个Filter会拦截所有的URL请求,并且对这些URL请求进行Spring Security的验证。
-->
< 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>
< servlet>
< servlet-name>index< /servlet-name>
< servlet-class>com.zsw.web.servlet.Index< /servlet-class>
< /servlet>
< servlet-mapping>
< servlet-name>index< /servlet-name>
< url-pattern>/index< /url-pattern>
< /servlet-mapping>
< listener>
< listener-class>org.springframework.web.context.ContextLoaderListener< /listener-class>
< /listener>
< listener>
< listener-class>com.zsw.web.loader.ServletContextLoaderListener< /listener-class>
< /listener>
< /web-app>
< web-app id= "Yoda" version= "2.4" xmlns= "http://java.sun.com/xml/ns/j2ee"
xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation= "http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" >
< display-name>Yoda< /display-name>
<!--- Spring ApplicationContext Definition -->
< context-param>
< param-name>contextConfigLocation< /param-name>
< param-value>/WEB-INF/classes/applicationContext-*.xml< /param-value>
< /context-param>
<!---
Spring security Filter
这个Filter会拦截所有的URL请求,并且对这些URL请求进行Spring Security的验证。
-->
< 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>
< servlet>
< servlet-name>index< /servlet-name>
< servlet-class>com.zsw.web.servlet.Index< /servlet-class>
< /servlet>
< servlet-mapping>
< servlet-name>index< /servlet-name>
< url-pattern>/index< /url-pattern>
< /servlet-mapping>
< listener>
< listener-class>org.springframework.web.context.ContextLoaderListener< /listener-class>
< /listener>
< listener>
< listener-class>com.zsw.web.loader.ServletContextLoaderListener< /listener-class>
< /listener>
< /web-app>
8.2applicationContext-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-2.5.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd ">
< beans:bean id= "loggerListener" class= "org.springframework.security.event.authentication.LoggerListener" />
< http access-denied-page= "/403.jsp" >
< intercept-url pattern= "/static/**" filters= "none" />
< intercept-url pattern= "/template/**" filters= "none" />
< intercept-url pattern= "/" filters= "none" />
< intercept-url pattern= "/login.jsp" filters= "none" />
<!--- 登录认证 -->
< form-login login-page= "/login.jsp" authentication-failure-url= "/login.jsp?error=true" default-target-url= "/index" />
<!--- 注销处理 -->
< logout logout-success-url= "/login.jsp" />
<!--- 基本认证 -->
< http-basic />
< /http>
< authentication-manager alias= "authenticationManager" />
<!--- 配置UserDetailsService来指定用户和权限 -->
< authentication-provider user-service-ref= "securityManager" >
< password-encoder hash= "md5" />
< /authentication-provider>
< beans:bean id= "accessDecisionManager" class= "org.springframework.security.vote.AffirmativeBased" >
< beans:property name= "allowIfAllAbstainDecisions" value= "false" />
< beans:property name= "decisionVoters" >
< beans:list>
< beans:bean class= "org.springframework.security.vote.RoleVoter" />
< beans:bean class= "org.springframework.security.vote.AuthenticatedVoter" />
< /beans:list>
< /beans:property>
< /beans:bean>
<!---
由于我们所实现的是FilterSecurityInterceptor中的一个开放接口,
所以我们实际上定义了一个新的bean,
并通过<custom-filter after="LAST" />插入到过滤器链中去。
-->
< beans:bean id= "resourceSecurityInterceptor" class= "org.springframework.security.intercept.web.FilterSecurityInterceptor" >
< beans:property name= "authenticationManager" ref= "authenticationManager" />
< beans:property name= "accessDecisionManager" ref= "accessDecisionManager" />
< beans:property name= "objectDefinitionSource" ref= "secureResourceFilterInvocationDefinitionSource" />
< beans:property name= "observeOncePerRequest" value= "false" />
< custom-filter after= "LAST" />
< /beans:bean>
< beans:bean id= "secureResourceFilterInvocationDefinitionSource" class= "com.zsw.security.interceptor.SecureResourceFilterInvocationDefinitionSource" />
< /beans:beans>
< 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-2.5.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd ">
< beans:bean id= "loggerListener" class= "org.springframework.security.event.authentication.LoggerListener" />
< http access-denied-page= "/403.jsp" >
< intercept-url pattern= "/static/**" filters= "none" />
< intercept-url pattern= "/template/**" filters= "none" />
< intercept-url pattern= "/" filters= "none" />
< intercept-url pattern= "/login.jsp" filters= "none" />
<!--- 登录认证 -->
< form-login login-page= "/login.jsp" authentication-failure-url= "/login.jsp?error=true" default-target-url= "/index" />
<!--- 注销处理 -->
< logout logout-success-url= "/login.jsp" />
<!--- 基本认证 -->
< http-basic />
< /http>
< authentication-manager alias= "authenticationManager" />
<!--- 配置UserDetailsService来指定用户和权限 -->
< authentication-provider user-service-ref= "securityManager" >
< password-encoder hash= "md5" />
< /authentication-provider>
< beans:bean id= "accessDecisionManager" class= "org.springframework.security.vote.AffirmativeBased" >
< beans:property name= "allowIfAllAbstainDecisions" value= "false" />
< beans:property name= "decisionVoters" >
< beans:list>
< beans:bean class= "org.springframework.security.vote.RoleVoter" />
< beans:bean class= "org.springframework.security.vote.AuthenticatedVoter" />
< /beans:list>
< /beans:property>
< /beans:bean>
<!---
由于我们所实现的是FilterSecurityInterceptor中的一个开放接口,
所以我们实际上定义了一个新的bean,
并通过<custom-filter after="LAST" />插入到过滤器链中去。
-->
< beans:bean id= "resourceSecurityInterceptor" class= "org.springframework.security.intercept.web.FilterSecurityInterceptor" >
< beans:property name= "authenticationManager" ref= "authenticationManager" />
< beans:property name= "accessDecisionManager" ref= "accessDecisionManager" />
< beans:property name= "objectDefinitionSource" ref= "secureResourceFilterInvocationDefinitionSource" />
< beans:property name= "observeOncePerRequest" value= "false" />
< custom-filter after= "LAST" />
< /beans:bean>
< beans:bean id= "secureResourceFilterInvocationDefinitionSource" class= "com.zsw.security.interceptor.SecureResourceFilterInvocationDefinitionSource" />
< /beans:beans>
9. 以上Demo下载地址:
http://download.csdn.net/source/3500432