spring security框架出来很久了,之前也研究过一段时间,现在有时间刚好整理一下。
这次做的,是全数据库配置,5张表。用户,角色,资源,用户-角色映射,角色资源映射。当然还可以进一步的扩充,菜单表,用户菜单表。
jar包什么的,可以直接从官网下,就不再说了,先从web.xml配置说起。
security 的filter,拦截全部的请求:
<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>
security的listenter:
<listener> <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> </listener>
如果想要用到srping的mvc的话,可以配置servlet:
<servlet> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
当然,这里可以配置多个servlet来处理类型的不同的请求,比如.do结尾的,比如.action结尾的,比如spring rest的URL的等等,只需要<servlet-name>不同就可以了,以及注意<load-on-startup>的先后顺序。
注意的是如果配置了org.springframework.web.servlet.DispatcherServlet,需要有一个与该<servlet-name>名字匹配的xml配置文件,系统会去默认加载,如<servlet-name>mvc</servlet-name>,则对应mvc-servlet.xml,里面可以没有实质的内容。
接下来就是最总要的applicationContext-sercurity.xml配置文件了:
<!-- auto-config="true" 设置为true时,安照默认的filter顺序加载,详见官方文档 --> <http auto-config="true" use-expressions="true" access-denied-page="/error/403.jsp"> <!-- 允许访问commons下的资源以及登陆界面 --> <intercept-url pattern="/commons/**" filters="none" /> <!-- 错误信息页面 --> <intercept-url pattern="/error/**" filters="none" /> <!-- 指定登录页面及登录失败跳转页 --> <form-login login-page="/error/404.jsp" authentication-failure-url="/manager/login.jsp?login_error=1" default-target-url="/manager/manager.jsp" /> <!-- 登出之后跳转页面 --> <logout invalidate-session="true" logout-success-url="/manager/login.jsp" logout-url="/j_spring_security_logout" /> <!-- 保证一个用户同时只能登入一次 --> <session-management> <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" /> </session-management> <!-- 检测失效的sessionId,超时时定位到另外一个URL --> <session-management invalid-session-url="/sessionTimeout.jsp" /> <!-- 增加一个自定义的filter,放在FILTER_SECURITY_INTERCEPTOR之前,实现用户、角色、权限、资源的数据库管理。 --> <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" /> </http> <!-- 一个自定义的filter,必须包含authenticationManager,accessDecisionManager,securityMetadataSource三个属性。 --> <beans:bean id="myFilter" class="com.core.security.MyFilterSecurityInterceptor"> <beans:property name="authenticationManager" ref="authenticationManager" /> <beans:property name="accessDecisionManager" ref="myAccessDecisionManager" /> <beans:property name="securityMetadataSource" ref="securityMetadataSource" /> </beans:bean> <!-- 认证管理器 --> <!-- 注意能够为authentication-manager 设置alias别名 --> <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref="myUserDetailService"> <!-- 加密 --> <password-encoder hash="md5" /> </authentication-provider> </authentication-manager> <!-- 接口实现 --> <!-- 用户验证,注入userService --> <beans:bean id="myUserDetailService" class="com.core.security.MyUserDetailService"> <beans:property name="userService" ref="userService" /> </beans:bean> <!-- 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 --> <beans:bean id="myAccessDecisionManager" class="com.core.security.MyAccessDecisionManager" /> <!-- 资源源数据定义,即定义某一资源可以被哪些角色访问 --> <!-- 无法注入,采用构造器加载 --> <beans:bean id="securityMetadataSource" class="com.core.security.MyInvocationSecurityMetadataSource"> <beans:constructor-arg> <beans:ref bean="roleService" /> </beans:constructor-arg> </beans:bean> <!-- 加载JDBC properties文件 --> <!-- 原加载类org.springframework.beans.factory.config.PropertyPlaceholderConfigurer --> <!-- 配置文件中数据库配置为加密之后内容,加载时需要对其进行解密 --> <beans:bean id="propertyConfigurer" class="com.core.commons.DBEncryption"> <beans:property name="locations"> <beans:list> <beans:value>classpath*:/com/conf/jdbc.properties</beans:value> </beans:list> </beans:property> </beans:bean>
其他的就是一些数据源等等配置文件了。
接下来是需要自己实现的几个接口:
MyAccessDecisionManager:
package com.core.security; import java.util.Collection; import java.util.Iterator; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; //@Service("myAccessDecisionManager") public class MyAccessDecisionManager implements AccessDecisionManager { // In this method, need to compare authentication with configAttributes. // 1, A object is a URL, a filter was find permission configuration by this // URL, and pass to here. // 2, Check authentication has attribute in permission configuration // (configAttributes) // 3, If not match corresponding authentication, throw a // AccessDeniedException. // 权限判断 检查用户是否拥有访问该URL资源所需的角色 public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if (configAttributes == null) { return; } //System.out.println("cause MyAccessDecisionManager decide " + object.toString()); // object is a URL. Iterator<ConfigAttribute> ite = configAttributes.iterator(); while (ite.hasNext()) { ConfigAttribute ca = ite.next(); String needRole = ((SecurityConfig) ca).getAttribute(); for (GrantedAuthority ga : authentication.getAuthorities()) { //System.out.println("cause " +needRole+":"+ga.getAuthority()); if (needRole.equals(ga.getAuthority())) { // ga is user's role. return; } } } throw new AccessDeniedException("no right"); } public boolean supports(ConfigAttribute attribute) { return true; } public boolean supports(Class<?> clazz) { return true; } }
MyFilterSecurityInterceptor:
package com.core.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 MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { private FilterInvocationSecurityMetadataSource securityMetadataSource; // ~ Methods // ======================================================================================================== /** * Method that is actually called by the filter chain. Simply delegates to * the {@link #invoke(FilterInvocation)} method. * * @param request * the servlet request * @param response * the servlet response * @param chain * the filter chain * * @throws IOException * if the filter chain fails * @throws ServletException * if the filter chain fails */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //System.out.println("cause FilterInvocationSecurityMetadataSource doFilter"); FilterInvocation fi = new FilterInvocation(request, response, chain); invoke(fi); } public Class<? extends Object> getSecureObjectClass() { return FilterInvocation.class; } public void invoke(FilterInvocation fi) throws IOException, ServletException { InterceptorStatusToken token = super.beforeInvocation(fi); try { fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.afterInvocation(token, null); } } public SecurityMetadataSource obtainSecurityMetadataSource() { return this.securityMetadataSource; } public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() { return securityMetadataSource; } public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) { this.securityMetadataSource = securityMetadataSource; } //@Override public void destroy() { } //@Override public void init(FilterConfig arg0) throws ServletException { } }
MyInvocationSecurityMetadataSource:
package com.core.security; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; 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 org.springframework.security.web.util.AntUrlPathMatcher; import org.springframework.security.web.util.UrlMatcher; import com.core.role.model.Role; import com.core.role.service.RoleService; import com.core.user.service.UserService; /** * * 此类在初始化时,应该取到所有资源及其对应角色的定义 * * @author cause * */ public class MyInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { private UrlMatcher urlMatcher = new AntUrlPathMatcher(); private static Map<String, Collection<ConfigAttribute>> resourceMap = null; private RoleService roleService; private UserService userService; Logger log = Logger.getLogger(MyInvocationSecurityMetadataSource.class.getName()); public MyInvocationSecurityMetadataSource(RoleService roleService) { this.roleService = roleService; loadResourceDefine(); } // 初始化角色-资源信息 public void loadResourceDefine() { resourceMap = new HashMap<String, Collection<ConfigAttribute>>(); Collection<ConfigAttribute> atts; ConfigAttribute ca; List<Role> roleList = roleService.getAllRole(); List<String> rescList; for (int i = 0; i < roleList.size(); i++) { ca = new SecurityConfig(roleList.get(i).getName()); atts = new ArrayList<ConfigAttribute>(); atts.add(ca); rescList = roleService.getRescByRoleID(roleList.get(i).getId()); for (int j = 0; j < rescList.size(); j++) { //System.out.println(roleList.get(i).getName()+":"+rescList.get(j)); resourceMap.put(rescList.get(j), atts); } } // ca = new SecurityConfig("ROLE_ADMIN"); // atts = new ArrayList<ConfigAttribute>(); // atts.add(ca); // //resourceMap.put("/**", atts); // //resourceMap.put("/manager/**", atts); // // ca = new SecurityConfig("ROLE_USER"); // atts = new ArrayList<ConfigAttribute>(); // atts.add(ca); // //resourceMap.put("/test/user/**", atts); // resourceMap.put("/manager/**", atts); // //resourceMap.put("/user.do**", atts); } // According to a URL, Find out permission configuration of this URL. // 获取访问的URL资源所需要的角色 // 项目启动时加载,需要注入数据源,相关信息从数据库读取 public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { // System.out.println("cause MyInvocationSecurityMetadataSource getAttributes"); // guess object is a URL. String url = ((FilterInvocation) object).getRequestUrl(); log.info("user acces URL = "+url); Iterator<String> ite = resourceMap.keySet().iterator(); while (ite.hasNext()) { String resURL = ite.next(); // System.out.println("pathMatchesUrl1 "+resURL+":"+url+":"+urlMatcher.pathMatchesUrl(resURL, // url)); // urlMatcher.pathMatchesUrl(url, resURL) // resURL-资源串(根据该资源串查询角色) url-当前访问的资源 if (urlMatcher.pathMatchesUrl(resURL, url)) { Collection<ConfigAttribute> ca = resourceMap.get(resURL); // System.out.println("cause check "+ca); return ca; } } // 避免因为返回空导致decide不执行 Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>(); ConfigAttribute ca = new SecurityConfig("ROLE_NO_USER"); atts.add(ca); return atts; } public boolean supports(Class<?> clazz) { return true; } public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } public UserService getUserService() { return userService; } public void setUserService(UserService userService) { this.userService = userService; } public RoleService getRoleService() { return roleService; } public void setRoleService(RoleService roleService) { this.roleService = roleService; } }
MyUserDetailService:
package com.core.security; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.springframework.dao.DataAccessException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.GrantedAuthorityImpl; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import com.core.user.model.MyUser; import com.core.user.service.UserService; public class MyUserDetailService implements UserDetailsService { private UserService userService; // @Override // 加载用户信息 // 需要数据源,在这里加载用户的信息,包括用户的密码、状态、角色、权限等 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>(); GrantedAuthorityImpl auth; // admin = new GrantedAuthorityImpl("ROLE_ADMIN"); // GrantedAuthorityImpl auth_manager = new // GrantedAuthorityImpl("ROLE_MANAGER"); // GrantedAuthorityImpl auth_user = new // GrantedAuthorityImpl("ROLE_USER"); // User user = null; // get user MyUser myUser = userService.getUserByUserName(username); // get role if (myUser != null) { List<String> roleList = userService.getRoleByUserID(myUser.getId()); for (int i = 0; i < roleList.size(); i++) { // System.out.println(username+":"+roleList.get(i)); auth = new GrantedAuthorityImpl(roleList.get(i)); auths.add(auth); } myUser.setAuthorities(auths); } else { throw new UsernameNotFoundException("usernameNotFound"); } // 硬编码,且该user为security的user // if (username.toUpperCase().equals("ADMIN")) { // auths = new ArrayList<GrantedAuthority>(); // auths.add(auth_admin); // auths.add(auth_manager); // auths.add(auth_user); // user = new User(username, "admin", true, true, true, true, auths); // myUser.setAuthorities(auths); // } else if (username.toUpperCase().equals("USER")) { // auths = new ArrayList<GrantedAuthority>(); // auths.add(auth_user); // user = new User(username, "user", true, true, true, true, auths); // myUser.setAuthorities(auths); // } return myUser; } public void setUserService(UserService userService) { this.userService = userService; } }
因为我的采用的是hibernate,以及spring的依赖注入,所以上述代码中,userService是service层,自己可以通过其他方式实现。
至此,核心的配置就完成了。
附带表结构:
CREATE TABLE `menu` ( `id` bigint(20) NOT NULL auto_increment, `name` varchar(255) NOT NULL default '', `url` varchar(255) default '', `parentId` bigint(20) NOT NULL default '-1', `sort` int(11) default '0', PRIMARY KEY (`id`), UNIQUE KEY `unique` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `menu_role` ( `menu_id` bigint(20) NOT NULL default '0', `role_id` bigint(20) NOT NULL default '0', UNIQUE KEY `unique` (`menu_id`,`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `resc` ( `id` bigint(20) NOT NULL auto_increment, `name` varchar(255) default NULL, `resc_type` varchar(255) default NULL, `resc_string` varchar(255) default NULL, `priority` int(11) default NULL, `descn` varchar(255) default NULL, PRIMARY KEY (`id`), UNIQUE KEY `unique` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `resc_role` ( `resc_id` bigint(20) NOT NULL default '0', `role_id` bigint(20) NOT NULL default '0', UNIQUE KEY `unique` (`resc_id`,`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `user_role` ( `user_id` bigint(20) NOT NULL default '0', `role_id` bigint(20) NOT NULL default '0', UNIQUE KEY `unique` (`user_id`,`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `role` ( `id` bigint(20) NOT NULL auto_increment, `name` varchar(255) NOT NULL default '', `descn` varchar(255) NOT NULL default '', PRIMARY KEY (`id`), UNIQUE KEY `unique` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `user` ( `id` bigint(20) NOT NULL auto_increment, `username` varchar(255) NOT NULL default '', `password` varchar(255) NOT NULL default '', `status` tinyint(1) NOT NULL default '1', `descn` varchar(255) NOT NULL default '', PRIMARY KEY (`id`), UNIQUE KEY `unique` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `user_role` ( `user_id` bigint(20) NOT NULL default '0', `role_id` bigint(20) NOT NULL default '0', UNIQUE KEY `unique` (`user_id`,`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
登录的action:<%=request.getContextPath()%>/j_spring_security_check"
登出的action:<%=request.getContextPath()%>//j_spring_security_logout"
相关推荐
Spring Security 实践指南 Spring Security 是一个基于 Java 的安全框架,旨在提供身份验证、授权和访问控制等功能。下面是 Spring Security 的主要知识点: 一、身份验证(Authentication) 身份验证是指对用户...
Spring Security 是一个强大的安全框架,主要用于Java应用的安全管理,它为Web应用和企业级应用提供了全面的安全服务。这个框架能够处理认证、授权以及各种安全相关的功能,帮助开发者构建安全、可扩展的应用。以下...
SpringSecurity是Java领域中一款强大的安全框架,主要用于Web应用程序的安全管理。它提供了全面的身份验证、授权、会话管理以及安全相关的功能,可以帮助开发者构建安全的Web应用。在本笔记中,我们将深入探讨Spring...
Spring Security是一个功能强大、高度定制的安全框架,它专门用于为基于Spring的应用程序提供安全性解决方案。Spring Security架构的设计初衷是为了解决认证和授权的需求,确保应用程序的安全性。它提供了全面的安全...
Spring Security 是一个强大的安全框架,用于为Java应用提供身份验证和授权服务。在这个完整的项目实例中,我们将深入探讨Spring Security的核心概念以及如何将其应用于实际的Web应用程序开发。 首先,我们从用户、...
在压缩包文件`spring_gateway_security_webflux`中,可能包含了示例代码或配置文件,用于演示如何在Spring Cloud Gateway中集成Spring Security,实现统一登录认证鉴权。这些资源可以帮助开发者更快地理解和实践上述...
在"springsecurity学习笔记"中,你可能会涉及以下主题: - Spring Security的基本配置,包括web安全配置和全局安全配置。 - 如何自定义认证和授权流程,比如实现自定义的AuthenticationProvider和...
SpringBoot+SpringSecurity处理Ajax登录请求问题 SpringBoot+SpringSecurity处理Ajax登录请求问题是SpringBoot开发中的一個常见问题,本文将详细介绍如何使用SpringBoot+SpringSecurity处理Ajax登录请求问题。 ...
Spring Security 是一个强大的安全框架,用于为Java应用提供全面的安全管理解决方案。它是Spring生态系统的组成部分,专注于身份验证、授权和访问控制。Spring Security的核心特性包括: 1. **身份验证...
SpringSecurity是Java开发中用于构建安全Web应用的框架,它提供了强大的身份验证、授权和访问控制功能。在本文中,我们将深入探讨SpringSecurity的核心概念、关键组件以及如何配置和使用这个框架。 首先,Spring...
Spring Security是Spring生态体系中的一个核心组件,主要负责应用程序的安全性,包括认证和授权。它为Web应用提供了全面的保护,防止未经授权的访问和操作。在版本2.5时,Spring Security已经是一个成熟且功能丰富的...
Spring Security是一个功能强大且高度可定制的身份验证和授权框架,专门用于保护Java应用程序的安全性。它构建在Spring Framework基础之上,提供了全面的安全解决方案,包括身份验证、授权、攻击防护等功能。 Spring...
### Spring Security 3.0.1 中文版知识点解析 #### 一、Spring Security 3.0.1 概览 ##### 1.1 Spring Security 是什么? Spring Security 是一个强大的、高度可定制的身份验证和访问控制框架。它提供了许多功能...
视频详细讲解,需要的小伙伴自行网盘下载,链接见附件,永久有效。 首先,SSM环境中我们通过xml配置的...Springsecurity在两种不同的开发模式中使用,有经典的独立web后台管理系统,也有时下最流行的前后端分离场景。
Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架,它是安全领域中Spring生态系统的一部分。Spring Security旨在为Java应用程序提供一个全面的安全解决方案,尤其适用于企业级应用场景。它主要...
### Spring Security 概述与应用实践 #### 一、引言 在当今互联网时代,网络安全问题日益凸显,尤其是Web应用程序的安全性受到了前所未有的关注。为了应对这些挑战,Spring Security 应运而生,成为了一个非常重要...
Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,用于Java应用程序。它提供了全面的安全解决方案,包括用户认证、权限授权、会话管理、CSRF防护以及基于HTTP的访问控制。在这个例子中,我们将...
SpringSecurity是Java领域中一款强大的安全框架,专为Spring和Spring Boot应用设计,提供全面的安全管理解决方案。在SpringBoot Web开发中,SpringSecurity扮演着核心角色,负责处理身份验证、授权以及访问控制等...
Spring Security 是一个强大的安全框架,用于为Java应用提供安全控制。在传统的权限管理中,权限配置通常硬编码在应用程序中,这使得权限调整变得困难,每次变动都需要重新部署应用。然而,通过动态授权,我们可以将...
Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,用于Java应用程序。在这个场景中,我们关注的是如何使用Spring Security实现登录验证以及在登录过程中传递参数,特别是记录并返回用户登录前的...