Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
来到公司后老大给的任务是项目的权限拦截功能开发,因为以前自己使用的过shiro做过感觉应该就这么简单,但是接下来我有了一点点的小头疼,因为老大要求我使用springsecurity来做权限的拦截。于是乎我就找各种的关于security的教程和在官网找例子,但是都不是很详细。然后就自己通过官网和所有的示例总结出了自己的现在这些经验和示例代码,希望对后来有需要使用到security的小伙伴带来小小的帮助!!! 好了不多说了 直接贴大家都期待和想看到的代码。哈哈
首先是数据库的表格部分代码:
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` varchar(50) NOT NULL COMMENT '用户Id',
`phone_number` varchar(11) DEFAULT NULL COMMENT '手机号',
`user_name` varchar(50) DEFAULT NULL COMMENT '用户名称',
`user_name_pinyin` varchar(100) DEFAULT NULL COMMENT '用户名拼音',
`email` varchar(50) DEFAULT NULL COMMENT '已绑定邮箱',
`openid` varchar(100) DEFAULT NULL COMMENT 'openid',
`is_subscribe` varchar(2) DEFAULT NULL COMMENT '是否关注',
`wechat` varchar(255) DEFAULT NULL COMMENT '已绑定微信号',
`org_id` varchar(50) DEFAULT NULL COMMENT '组织机构Id',
`org_name` varchar(100) DEFAULT NULL COMMENT '组织机构名称',
`position` varchar(100) DEFAULT NULL COMMENT '职位',
`tenant_id` varchar(50) DEFAULT NULL COMMENT '租户Id',
`sex` int(11) DEFAULT NULL COMMENT '性别(0:代表男 1:代表女)',
`photo` varchar(255) DEFAULT NULL COMMENT '用户头像源路径',
`centralGraph` varchar(255) DEFAULT NULL COMMENT '用户头像中图',
`thumbnails` varchar(255) DEFAULT NULL COMMENT '用户头像小图',
`birthday` datetime DEFAULT NULL COMMENT '生日',
`address` varchar(255) DEFAULT NULL COMMENT '居住地址',
`status` int(11) DEFAULT NULL COMMENT '人员状态:1.已激活、2.未激活、3.已禁用、4.未分配部门、89.离职、',
`creater` varchar(50) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`modifyer` varchar(50) DEFAULT NULL COMMENT '修改人',
`modify_time` datetime DEFAULT NULL COMMENT '修改时间',
`device_token` varchar(50) DEFAULT NULL COMMENT '设备token 手机唯一标识 web端可为空',
`device_type` int(11) DEFAULT NULL COMMENT '设备类型0其他 1:IOS 2:Android 3:pc',
`reserve_1` varchar(20) DEFAULT NULL COMMENT '预留字段1',
`reserve_2` varchar(20) DEFAULT NULL COMMENT '预留字段2',
`reserve_3` varchar(20) DEFAULT NULL COMMENT '预留字段3',
`user_number` varchar(20) DEFAULT NULL COMMENT '员工编号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8COMMENT='系统用户表';
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`id` varchar(50) NOT NULL COMMENT '主键',
`creater_id` varchar(50) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`modifyer_id` varchar(50) DEFAULT NULL,
`modify_time` datetime DEFAULT NULL,
`user_id` varchar(50) DEFAULT NULL COMMENT '用户的主键ID',
`role_id` varchar(50) DEFAULT NULL COMMENT '角色主键ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`role_id` varchar(50) NOT NULL COMMENT '角色主键id',
`role_name` varchar(150) DEFAULT NULL COMMENT '角色名称',
`org_code` varchar(100) DEFAULT NULL,
`org_name` varchar(100) DEFAULT NULL COMMENT '配置名称',
`descript` varchar(128) DEFAULT NULL,
`sort_num`int(11) DEFAULT NULL COMMENT '排序号',
`is_system` int(11) DEFAULT '0' COMMENT '是否为系统默认角色, 1:是; 2:否',
`creater_id` varchar(50) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`modifyer` varchar(50) DEFAULT NULL,
`modify_time` datetime DEFAULT NULL,
`reserve_1` varchar(20) DEFAULT NULL COMMENT '预留字段1',
`reserve_2` varchar(20) DEFAULT NULL COMMENT '预留字段2',
`reserve_3` varchar(20) DEFAULT NULL COMMENT '预留字段3',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
`id` varchar(50) NOT NULL COMMENT '主键',
`role_id` varchar(50) DEFAULT NULL COMMENT '角色主键ID',
`permission_id` varchar(50) DEFAULT NULL COMMENT '权限主键ID',
`creater_id` varchar(50) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`modifyer_id` varchar(50) DEFAULT NULL,
`modify_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`permission_id` varchar(50) NOT NULL COMMENT '权限主键id',
`org_code` varchar(100) DEFAULT NULL,
`org_name` varchar(100) DEFAULT NULL COMMENT '配置名称',
`parent_id` varchar(50) DEFAULT NULL,
`url` varchar(150) DEFAULT NULL,
`display` int(11) DEFAULT NULL COMMENT '选择权限时,是否显示该权限 2:不显示, 1显示',
`sort_number` int(11) DEFAULT NULL COMMENT '显示顺序',
`descritp` varchar(128) DEFAULT NULL COMMENT '权限描述',
`status` int(11) DEFAULT NULL COMMENT '有效:1;无效:0',
`creater_id` varchar(50) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`modifyer_id` varchar(50) DEFAULT NULL,
`modify_time` datetime DEFAULT NULL,
`reserve_1` varchar(20) DEFAULT NULL COMMENT '预留字段1',
`reserve_2` varchar(20) DEFAULT NULL COMMENT '预留字段2',
`reserve_3` varchar(20) DEFAULT NULL COMMENT '预留字段3',
PRIMARY KEY (`permission_id`),
KEY`AK_IDX_SP_DISPLAY` (`display`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
由于我们使用的是分表分库的设计,所以用户表中没有密码的字段,各位看客如果想运行需要自己去添加到自己的表格中
需要使用到的jar包:
<!-- springsecurity 所需jar包--> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-acl</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>${spring.security.version}</version> </dependency>
<spring.security.version>3.2.5.RELEASE</spring.security.version>
web.xml配置:
<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.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" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 不需要权限访问 --> <http pattern="/login.jsp" security="none"></http> <http pattern="/404.jsp" security="none"></http> <http pattern="/500.jsp" security="none"></http> <http pattern="/index.jsp" security="none"></http> <http pattern="/access.jsp" security="none"></http> <http pattern="/error.jsp" security="none"></http> <http pattern="/sessionTimeOut.jsp" security="none"/> <http pattern="/quitPage.jsp" security="none"/> <!--以上部分可根据自己的需求设定那些事不需要拦截的,然后直接放行就ok了--> <http auto-config='true' > <!-- 没有权限跳转页面 --> <access-denied-handler error-page="/access.jsp" /> <!-- 校验登陆可访问--> <intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" /> <form-login login-page="/system/loginpage" login-processing-url="/logincheck" authentication-failure-handler-ref="failureHandler" authentication-success-handler-ref="successHandler"/> <logout logout-url="/logout" logout-success-url="/system/loginpage" /> <!--session 不做处理--> <session-management invalid-session-url="/system/loginpage" session-fixation-protection="none" > <concurrency-control max-sessions="1" error-if-maximum-exceeded="false" expired-url="/system/loginpage" /> </session-management> <!-- 1、注释此过滤器,不再验证是否有访问权限(访问所有资源不再判断是否具有权限) 2、注释此过滤器,并更改max-sessions="9999",可用一个账号登陆9999次,并且不再验证是否有访问权限(访问所有资源不再判断是否具有权限) --> <custom-filter ref="mySecurityFilter" before="FILTER_SECURITY_INTERCEPTOR" /> </http> <authentication-manager alias="authManager" erase-credentials="false" > <authentication-provider user-service-ref="userServiceDetail"> <password-encoder ref="passwordEncoder"> </password-encoder> </authentication-provider> </authentication-manager> <!-- SHA加密方式 --> <beans:bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" /> <beans:bean id="dubboAop" class="com.thinkwin.web.DubboServiceContextAop" /> <aop:config> <aop:aspect id="dubboAspect" ref="dubboAop" > <aop:before method="dubboContext" pointcut-ref="pointCutBefore" /> </aop:aspect> </aop:config> <!-- 登录失败后业务处理 --> <beans:bean id="failureHandler" class="com.xxxx
.web.security.LoginAuthenticationFailureHandler"> <beans:property name="userService" ref="userService"></beans:property> <beans:property name="sysLogService" ref="sysLogService"></beans:property> <beans:property name="loginRegisterService" ref="loginRegisterService"></beans:property> </beans:bean> <!-- 登录成功业务处理 --> <beans:bean id="successHandler" class="com.xxxx
.web.security.LoginAuthenticationSuccesssHandler"> <beans:property name="loginRegisterService" ref="loginRegisterService"></beans:property> <beans:property name="sysLogService" ref="sysLogService"></beans:property> <beans:property name="userService" ref="userService"></beans:property> <beans:property name="saasTenantService" ref="saasTenantCoreService"></beans:property> <beans:property name="defaultUrl" value="/index.do"></beans:property> <!-- 可变换登录成功后的路径,验证用户是否拥有该权限 --> </beans:bean> <!-- 自定义过滤器 --> <beans:bean id="mySecurityFilter" class="com.xxxx
.web.security.MyFilterSecurityInterceptor"> <beans:property name="accessDecisionManager" ref="accessDescisionManager"></beans:property> <beans:property name="fisMetadataSource" ref="securityMetadataSource"></beans:property> <beans:property name="authenticationManager" ref="authManager"></beans:property> </beans:bean> <beans:bean id="securityMetadataSource" class="com.xxxx
.web.security.MySecurityMetadataSource"> <beans:constructor-arg name="rolePermissionService" ref="rolePermissionService"></beans:constructor-arg> </beans:bean> <beans:bean id="accessDescisionManager" class="com.xxxx.web.security.MyAccessDescisionManager"> </beans:bean> <beans:bean id="userServiceDetail" class="com.xx.web.security.MyUserDetailServiceImpl"><beans:property name="userService" ref="userService"></beans:property> <beans:property name="rolePermissionService" ref="rolePermissionService"> </beans:property> <beans:property name="permissionService" ref="permissionService"> </beans:property> <beans:property name="userRoleService" ref="userRoleService"> </beans:property> <beans:property name="loginRegisterService" ref="saasTenantCoreService"> </beans:property> </beans:bean></beans:beans>
security需要使用的的几个主要的类:
LoginAuthenticationFailureHandler 登录失败跳转的类
import org.apache.commons.lang.StringUtils; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * 验证失败页面 * @author yincl * */ public class LoginAuthenticationFailureHandler implements AuthenticationFailureHandler { //@Autowired private UserService userService; private LoginRegisterService loginRegisterService; private SysLogService sysLogService; public void setUserService(UserService userService) { this.userService = userService; } public void setLoginRegisterService(LoginRegisterService loginRegisterService) { this.loginRegisterService = loginRegisterService; } public void setSysLogService(SysLogService sysLogService) { this.sysLogService = sysLogService; } public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException authentication) throws IOException, ServletException { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); PrintWriter out = response.getWriter(); //增加操作日志 sysLogService.createLog(BusinessType.loginOp.toString(), EventType.platform_login.toString(),"登录失败","", Loglevel.error.toString(),ip,source); out.println("{\"code\":\"0\",\"url\":\"\"}"); } }
LoginAuthenticationSuccesssHandler 登录成功跳转的类
import org.apache.commons.lang.StringUtils; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.*; /** * 验证成功页面, * 根据url跳转 * @author yincl * */ public class LoginAuthenticationSuccesssHandler implements AuthenticationSuccessHandler { private String defaultUrl; private LoginRegisterService loginRegisterService; private SysLogService sysLogService; private UserService userService; private SaasTenantService saasTenantService; public void setSaasTenantService(SaasTenantService saasTenantService) { this.saasTenantService = saasTenantService; } public void setLoginRegisterService(LoginRegisterService loginRegisterService) { this.loginRegisterService = loginRegisterService; } public void setSysLogService(SysLogService sysLogService) { this.sysLogService = sysLogService; } public void setUserService(UserService userService) { this.userService = userService; } /* (non-Javadoc) * @see org.springframework.security.web.authentication.AuthenticationSuccessHandler#onAuthenticationSuccess(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication) */ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { String userName = request.getParameter("j_username"); Map map = new HashMap<>(); if(ValidatorUtil.isMobile(userName)) { SaasUserWeb saasUserWeb = new SaasUserWeb(); saasUserWeb.setAccount(userName); SaasUserWeb user = saasTenantService.selectUserLoginInfo(saasUserWeb); map.put("Id",user.getId()); map.put("userId",user.getUserId()); map.put("tentantId",user.getTenantId()); map.put("time",user.getLastLoginTime()); }else{ SaasUserOauth saasUserOauth = new SaasUserOauth(); saasUserOauth.setOauthUnionId(userName); List<SaasUserOauth> saasUserOauth1 = saasTenantService.selectOAuthLoginInfo(saasUserOauth); String newUserId = saasUserOauth1.get(0).getUserId(); if(StringUtils.isNotBlank(newUserId)){ SaasUserWeb saasUserWeb = new SaasUserWeb(); saasUserWeb.setUserId(newUserId); SaasUserWeb newUser = saasTenantService.selectUserLoginInfo(saasUserWeb); if(null != newUser){ Date timee = newUser.getLastLoginTime();//最后登录时间 if(null != timee){ map.put("time",timee); } map.put("Id",newUser.getId()); } } map.put("userId",saasUserOauth1.get(0).getUserId()); map.put("tentantId",saasUserOauth1.get(0).getTenantId()); } Collection<? extends GrantedAuthority> list = authentication.getAuthorities(); response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); PrintWriter out = response.getWriter(); if( list == null || list.size() == 0 ){ out.println("{\"code\":\"0\",\"url\":\"\"}"); return; } if(StringUtils.isNotBlank((String) map.get("Id"))) { SaasUserWeb saasUserWeb1 = new SaasUserWeb(); saasUserWeb1.setId((String) map.get("Id")); saasUserWeb1.setLastTimeLogin((Date) map.get("time")); saasUserWeb1.setLastLoginTime(new Date()); saasTenantService.updateUserLoginInfo(saasUserWeb1); } String userId = (String)map.get("userId"); String tokenn = CreateUUIdUtil.Uuid(); RedisUtil.set("xxxx." + (String)map.get("tentantId") +"."+userId,tokenn); RedisUtil.expire("xxxx." + (String)map.get("tentantId") +"."+userId,900); SaasTenant saasTenant = saasTenantService.selectSaasTenantServcie((String) map.get("tentantId")); if(null != saasTenant){ String tenantType = saasTenant.getTenantType(); if(StringUtils.isNotBlank(tenantType)){ tenantType1 = tenantType; } } SysUser sysUser = userService.selectUserByUserId(userId); String name = ""; if(null!=sysUser){ name = sysUser.getUserName(); } Integer status = sysUser.getStatus(); if(null != status && status == 3){ sysLogService.createLog(BusinessType.loginOp.toString(), EventType.platform_login.toString(),name+"登录失败","", Loglevel.error.toString(),ip,source); out.println("{\"code\":\"2\",\"msg\":\"您已被管理员禁用!\",\"url\":\"/disablePage.jsp \"}");//disablePage.jsp return; }else if (null != status && status == 89){ sysLogService.createLog(BusinessType.loginOp.toString(), EventType.platform_login.toString(),name+"登录失败","", Loglevel.error.toString(),ip,source); out.println("{\"code\":\"3\",\"msg\":\"您已在当前企业离职!\",\"userId\":\"" + userId + "\",\"url\":\"/quitPage.jsp \"}");//quitPage.jsp }else { if(null != status && status == 2){ SysUser sysUserr = new SysUser(); sysUserr.setId(sysUser.getId()); sysUserr.setStatus(1); userService.updateUserByUserId(sysUserr); } sysLogService.createLog(BusinessType.loginOp.toString(), EventType.platform_login.toString(), name + "登录成功", "", Loglevel.info.toString(), ip, source); //获取当前的sessionid值 String jsessionId = request.getSession().getId(); out.println("{\"code\":\"1\",\"msg\":\"查询成功!\",\"url\":\"/index.do\",\"jsessionid\":\"" + jsessionId + "\",\"tenantType\":\"" + tenantType1 + "\",\"userId\":\"" + userId + "\",\"token\":\"" + tokenn + "\"}"); } } public void setDefaultUrl(String defaultUrl) { this.defaultUrl = defaultUrl; } }
MyAccessDescisionManager 访问决策器类
import org.apache.commons.lang.StringUtils; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.web.FilterInvocation; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Collection; import java.util.Iterator; /** * @description 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 ;做最终的访问控制决定 */ public class MyAccessDescisionManager implements AccessDecisionManager { /** * @description 认证用户是否具有权限访问该url地址 * */ public void decide(Authentication authentication, Object obj, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException,InsufficientAuthenticationException { FilterInvocation fi = (FilterInvocation) obj; HttpServletRequest request = fi.getRequest(); if(configAttributes==null) return; Iterator<ConfigAttribute> it = configAttributes.iterator(); while(it.hasNext()){ String needRole = it.next().getAttribute(); for(GrantedAuthority ga:authentication.getAuthorities()){ if(needRole.equals(ga.getAuthority())){ return; } } } MyFilterSecurityInterceptor.goToUrl(obj, "/access.jsp"); throw new AccessDeniedException("--------MyAccessDescisionManager:decide-------权限认证失败!"); } /** * 启动时候被AbstractSecurityInterceptor调用,决定AccessDecisionManager是否可以执行传递ConfigAttribute。 */ public boolean supports(ConfigAttribute configAttribute) { return true; } /** * 被安全拦截器实现调用,包含安全拦截器将显示的AccessDecisionManager支持安全对象的类型 */ public boolean supports(Class<?> clazz) { return true; } }
MyFilterSecurityInterceptor 自定义拦截器
import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityMetadataSource; import org.springframework.security.access.intercept.AbstractSecurityInterceptor; import org.springframework.security.access.intercept.InterceptorStatusToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.Collection; /** * @description 一个自定义的filter, * 必须包含authenticationManager,accessDecisionManager,securityMetadataSource三个属性, 我们的所有控制将在这三个类中实现 */ public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { private Logger logger = Logger.getLogger(MyFilterSecurityInterceptor.class); //注入userService服务 private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } private FilterInvocationSecurityMetadataSource fisMetadataSource; public Class<?> getSecureObjectClass() { return FilterInvocation.class; } public SecurityMetadataSource obtainSecurityMetadataSource() { return fisMetadataSource; } public void destroy() {} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest)request; HttpServletResponse res = (HttpServletResponse) response; FilterInvocation fi = new FilterInvocation(request, response, chain); Collection<ConfigAttribute> attributes = fisMetadataSource.getAttributes(fi); String url1 = fi.getFullRequestUrl(); String token1 = request.getParameter("token"); if(url1.indexOf("/system") != -1 || url1.indexOf(".jsp") != -1){ this.publicSuccess(fi,(HttpServletRequest)request,(HttpServletResponse)response); } if(null != token1 && !"".equals(token1)) { TenantUser tenantUser = null; Authentication auth = SecurityContextHolder.getContext().getAuthentication(); try { tenantUser = (TenantUser) auth.getPrincipal(); } catch (Exception e) { publicError((HttpServletRequest) request,(HttpServletResponse) response, 1); return; } if(null != tenantUser){ //获取当前用户所在企业的租户id String tenantId = tenantUser.getTenantId(); if(StringUtils.isBlank(tenantId)){ publicError((HttpServletRequest) request,(HttpServletResponse) response, 1); return; } TenantContext.setTenantId(tenantId); //获取当前用户的主键id String userId = tenantUser.getUserId(); if(StringUtils.isBlank(userId)){ publicError((HttpServletRequest) request,(HttpServletResponse) response, 1); return; } //获取用户信息 SysUser sysUser = userService.selectUserByUserId(userId); if(null == sysUser){ //publicError((HttpServletResponse) response,1); publicError((HttpServletRequest) request,(HttpServletResponse) response, 1); return; } //获取用户状态 Integer userStatus = sysUser.getStatus(); if(null != userStatus && userStatus == 89){ logger.info("当前用户在当前企业下是离职状态!!!"); if(!isAjaxRequest) { goToUrl(fi, "/quitPage.jsp"); }else{ goToJsonUrl(fi,"/system/gotoQuitPage","当前用户在当前企业下是离职状态!!!","8"); } return; }else if(null != userStatus && userStatus == 3){ logger.info("当前用户在当前企业下是禁用状态!!!"); if(!isAjaxRequest) { goToUrl(fi, "/disablePage.jsp"); }else{ goToJsonUrl(fi,"/system/gotoDisablePage","当前用户在当前企业下是禁用状态!!!","9"); } return; } String tokenn = RedisUtil.get("xxxx." + tenantUser.getTenantId() +"."+tenantUser.getUserId()); if (!token1.equals(tokenn)) { HttpServletRequest req1 = (HttpServletRequest)request; HttpServletResponse res1 = (HttpServletResponse) response; publicError(req1,res1, 1); return; } else { RedisUtil.expire("xxxx." + tenantUser.getTenantId() + "."+tenantUser.getUserId(), 900); if (tenantUser != null) { TenantContext.setTenantId(tenantUser.getTenantId()); TenantUserVo tenantUserVo = new TenantUserVo(); tenantUserVo.setUserId(userId); tenantUserVo.setUserName(tenantUser.getUserName()); tenantUserVo.setTenantId(tenantUser.getTenantId()); tenantUserVo.setEmail(tenantUser.getEmail()); tenantUserVo.setIp(tenantUser.getIp()); tenantUserVo.setDevice(tenantUser.getDevice()); TenantContext.setUserInfo(tenantUserVo); } this.publicSuccess(fi, (HttpServletRequest) request, (HttpServletResponse) response); } } }else{ goToUrl(fi, "/access.jsp"); return; } } public void init(FilterConfig config) throws ServletException { } public static void goToUrl( Object obj,String url ){ FilterInvocation fi = (FilterInvocation) obj; HttpServletRequest request = fi.getRequest(); HttpServletResponse response = fi.getResponse(); response.setCharacterEncoding("UTF-8"); String responseUrl = request.getContextPath() + url; PrintWriter out = null; try { out = response.getWriter(); } catch (IOException e) { e.printStackTrace(); } out.println("<html>"); out.println("<script type=\"text/javascript\">"); out.println("window.open ('" + responseUrl + "','_top');"); out.println("</script>"); out.println("</html>"); } public static void goToJsonUrl( Object obj,String url,String msg,String code){ FilterInvocation fi = (FilterInvocation) obj; HttpServletResponse response = fi.getResponse(); response.setHeader("Content-type", "application/json;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); PrintWriter out = null; try { out = response.getWriter(); } catch (IOException e) { e.printStackTrace(); out.println("{\"code\":\"0\",\"msg\":\"操作失败!\"}"); } out.println("{\"code\":\""+code+"\",\"msg\":\""+msg+"\",\"url\":\"" + url + "\"}"); } public static void goToJsonUrl( HttpServletRequest request,HttpServletResponse response,String url,String msg,String code){ response.setHeader("Content-type", "application/json;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); PrintWriter out = null; try { out = response.getWriter(); } catch (IOException e) { e.printStackTrace(); out.println("{\"code\":\"0\",\"msg\":\"操作失败!\"}"); } out.println("{\"code\":\""+code+"\",\"msg\":\""+msg+"\",\"url\":\"" + url + "\"}"); } public void setFisMetadataSource( FilterInvocationSecurityMetadataSource fisMetadataSource) { this.fisMetadataSource = fisMetadataSource; } public void publicError(HttpServletRequest request,HttpServletResponse response,Integer status) throws IOException { boolean isAjaxRequest = false; if(!StringUtils.isBlank(request.getHeader("x-requested-with")) && request.getHeader("x-requested-with").equals("XMLHttpRequest")){ isAjaxRequest = true; } logger.error("出现异常:"); if(!isAjaxRequest) { String url = "/access.jsp"; if(null != status && status == 2){ logger.info("第二处error.jsp出现处!!!"); url = "/error.jsp"; } response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<script type=\"text/javascript\">"); out.println("window.open ('" + url + "','_top');"); out.println("</script>"); out.println("</html>"); }else { if(null != status && status == 2){ goToJsonUrl(request,response,"/system/gotoErrorPage","请求失败!!!","10"); } goToJsonUrl(request,response,"/system/loginpage","权限不足!!!","10"); } } public void publicSuccess(FilterInvocation fi,HttpServletRequest request,HttpServletResponse response) throws IOException { boolean isAjaxRequest = false; if(!StringUtils.isBlank(request.getHeader("x-requested-with")) && request.getHeader("x-requested-with").equals("XMLHttpRequest")){ isAjaxRequest = true; } InterceptorStatusToken token = super.beforeInvocation(fi); try { fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } catch (Exception e) { logger.error("出现异常:" + e.getMessage()); if(!isAjaxRequest) { String url = ""; if ("Access is denied".equals(e.getMessage())) { url = request.getContextPath() + "/access.jsp"; } else { logger.info("第三处error.jsp出现处!!!"); url = request.getContextPath() + "/error.jsp"; } response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<script type=\"text/javascript\">"); out.println("window.open ('" + url + "','_top');"); out.println("</script>"); out.println("</html>"); return; }else { response.setHeader("Content-type", "application/json;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); if ("Access is denied".equals(e.getMessage())) { goToJsonUrl(request,response,"/system/loginpage","权限不足!!!","10"); } else { logger.info("第三处error.jsp出现处!!!"); goToJsonUrl(request,response,"/system/gotoErrorPage","请求失败!!!","10"); } } }finally{ super.afterInvocation(token,null); } } }
MySecurityMetadataSource 资源数据定义类
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.util.AntPathMatcher; import java.util.*; /** * @description 资源源数据定义,将所有的资源和权限对应关系建立起来,即定义某一资源可以被哪些角色访问 */ public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource { //@Resource private UserService userService; //@Resource private RolePermissionService rolePermissionService; private AntPathMatcher urlMatcher = new AntPathMatcher(); private List<SysPermission> permissions = null; public MySecurityMetadataSource(UserService userService, RolePermissionService rolePermissionService) { this.userService = userService; this.rolePermissionService = rolePermissionService; loadResourcesDefine(); } public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } /** * 加载所有资源和权限的关系 */ //@PostConstruct public void loadResourcesDefine(){ ResourceMap.clean(); //加载所有的角色 List<SysRole> roles = userService.findAllRoles(); if(roles != null && roles.size() > 0) { for (SysRole role : roles) { //获取角色的资源信息 permissions = rolePermissionService.findResourcesByRoleId(role.getRoleId()); if(permissions != null && permissions.size() > 0) { for (SysPermission permission : permissions) { Collection<ConfigAttribute> configAttributes = null; ConfigAttribute configAttribute = new SecurityConfig(role.getRoleName()); if (ResourceMap.containsKey(permission.getUrl())) { configAttributes = ResourceMap.get(permission.getUrl()); configAttributes.add(configAttribute); } else { configAttributes = new ArrayList<ConfigAttribute>(); configAttributes.add(configAttribute); } ResourceMap.put(permission.getUrl(), configAttributes); } } } } } /* * 根据请求的资源地址,获取它所拥有的权限 * 返回请求的资源需要的权限 */ public Collection<ConfigAttribute> getAttributes(Object obj) throws IllegalArgumentException { //获取请求的url方法 String url = ((FilterInvocation)obj).getRequestUrl(); Collection<ConfigAttribute> urlSet = new HashSet<ConfigAttribute>(); if( url.indexOf("&") != -1 ) { url = url.substring(0, url.indexOf("&")); } //获取请求的url资源 String methodUrl = ""; if( url.indexOf("?") != -1 ) { methodUrl = url.substring(0, url.indexOf("?")); } Iterator<String> it = ResourceMap.ketSetIterator(); while(it.hasNext()){ String _url = it.next(); //如果该拥有url资源 if(!"".equals(methodUrl) && urlMatcher.match(methodUrl, _url)){ Iterator<ConfigAttribute> urlIt = ResourceMap.get(_url).iterator(); while( urlIt.hasNext() ){ urlSet.add(urlIt.next()); } //如果拥有方法资源 }else if(urlMatcher.match(url, _url)){ Iterator<ConfigAttribute> urlIt = ResourceMap.get(_url).iterator(); while( urlIt.hasNext() ){ urlSet.add(urlIt.next()); } } } //返回所有的角色 if( urlSet != null && urlSet.size() > 0 ) { return urlSet; } return null; } public boolean supports(Class<?> arg0) { return true; } }
MyUserDetailServiceImpl 权限验证类
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import java.util.*; /** * 权限验证 * @author Administrator * */ public class MyUserDetailServiceImpl implements UserDetailsService { private UserService userService; private RolePermissionService rolePermissionService; private PermissionService permissionService; private UserRoleService userRoleService; private SaasTenantService loginRegisterService; /** * @param userService the userService to set */ public void setUserService(UserService userService) { this.userService = userService; } public void setRolePermissionService(RolePermissionService rolePermissionService) { this.rolePermissionService = rolePermissionService; } public void setLoginRegisterService(SaasTenantService loginRegisterService) { this.loginRegisterService = loginRegisterService; } public void setUserRoleService(UserRoleService userRoleService) { this.userRoleService = userRoleService; } public void setPermissionService(PermissionService permissionService) { this.permissionService = permissionService; } /** * 点击登录后会调用此方法, * 获取用户的权限 */ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { boolean enabled = true; //用户帐号是否已启用 boolean accountNonExpired = true; //是否过期 boolean credentialsNonExpired = true; //用户凭证是否已经过期 boolean accountNonLocked = true; //是否锁定 Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>(); Map map = new HashMap<>(); // TenantContext.setTenantId("0"); //判断手机号格式是否正确 if(ValidatorUtil.isMobile(username)) { SaasUserWeb saasUserWeb = new SaasUserWeb(); saasUserWeb.setAccount(username); SaasUserWeb user1 = loginRegisterService.selectUserLoginInfo(saasUserWeb); if(null != user1){ map.put("tenantId",user1.getTenantId()); map.put("userId",user1.getUserId()); map.put("password",user1.getPassword()); map.put("account",user1.getAccount()); } }else{ SaasUserOauth saasUserOauth = new SaasUserOauth(); saasUserOauth.setOauthUnionId(username); //saasUserOauth.setOauthType(2); List<SaasUserOauth> saasUserOauth1 = loginRegisterService.selectOAuthLoginInfo(saasUserOauth); if(null != saasUserOauth1){ map.put("tenantId",saasUserOauth1.get(0).getTenantId()); map.put("userId",saasUserOauth1.get(0).getUserId()); map.put("password",saasUserOauth1.get(0).getPassword()); map.put("account",saasUserOauth1.get(0).getOauthUnionId()); } } if(null != map){ TenantContext.setTenantId((String)map.get("tenantId")); SysUser sysUser = userService.selectUserByUserId((String)map.get("userId")); if (sysUser == null) { enabled = false; } List<SysRole> roles = userRoleService.findUserRolesByUserId((String)map.get("userId")); if (null != roles && roles.size() > 0) { for (SysRole role : roles) { GrantedAuthority ga = new SimpleGrantedAuthority(role.getRoleName()); authorities.add(ga); List<SysRolePermission> perms = rolePermissionService.findPermsByRoleId(role.getRoleId()); if (null != perms && perms.size() > 0) { for (SysRolePermission rolePerm : perms) { SysPermission perm = permissionService.getPermissionById(rolePerm.getPermissionId()); GrantedAuthority perga = new SimpleGrantedAuthority(perm.getUrl()); authorities.add(perga); } } } } String userName = null; if(null != sysUser){ userName = sysUser.getUserName(); } map.put("userName",userName); }else{ enabled = false; } TenantUser tenantUser = new TenantUser( (String)map.get("account"), (String)map.get("password"), enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities, (String)map.get("tenantId") ); tenantUser.setEmail(""); tenantUser.setUserName(map.get("userName").toString()); tenantUser.setUserId(map.get("userId").toString()); return tenantUser; } }登录的jsp或者调用者需要使用到的字段如下:
<form id="userForm"action="logincheck" method="post" class="form1"> username:<input id="username" name=j_username type="text" /><br/><br/> password:<input id="password" name=j_password type="password" /><br/><br/> <input type="submit" value="login" onclick="fromSubmit()"> </form>
name=j_username和name=j_password 是必须的
好了如果把这些代码放在你的项目中 你就可以完全的玩转security的权限拦截了,哈哈!!!
小弟才疏学浅 ,如有不足之处望各位多多的指教!!!!
如要转发,请标明出处,谢谢!!!