最近在公司项目中遇到security2.0.8框架,遇到项目升级但是新版本的spring已经不支持2.0.8版本,并且4.2版本好像配置和以前版本有差异,去掉了很多类和方法,作为一个新入手的框架在网上搜了很多篇文章都不太详细,于是自己重新搭建了个新的demo,用到的是spring security4.2.7 springmvc4.3.18,spring4.3.18,springdata1.10.11,以及一些其他常用框架
完整的pom.xml如下:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>SSH</groupId>
<artifactId>SSH</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>SSH</name>
<description/>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.18.RELEASE</spring.version>
<hibernate.version>5.0.12.Final</hibernate.version>
</properties>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<!-- =============spring================ -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework</groupId>-->
<!--<artifactId>spring-test</artifactId>-->
<!--<version>${spring.version}</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- ====spring ===end===================================== -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- ====druid ===end===================================== -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.11</version>
</dependency>
<!-- ====ehcache ===end===================================== -->
<!-- ====json===start============================================== -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<!-- ====json===end============================================== -->
<!-- =====aspectj===start=============================================== -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.5</version>
</dependency>
<!-- =====aspectj===end=============================================== -->
<!-- ======hibernate==start======================================= -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- ====hibernate==end=================================== -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.10.11.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.3.4.ALL</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId>
<version>3.1.1.BETA</version>
</dependency>
<dependency>
<groupId>cn.jpush.api</groupId>
<artifactId>jpush-client</artifactId>
<version>3.3.7</version>
</dependency>
<dependency>
<groupId>cn.jpush.api</groupId>
<artifactId>jiguang-common</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.6</version>
</dependency>
<!-- ======slf4j==================== -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<!-- =====log4j2============================= -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.10.0</version>
</dependency>
<!-- ====commons帮助包=================================== -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<!-- ===velocity================================ -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
<version>2.0</version>
</dependency>
<!-- security========================== -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.7.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<version>3.1</version>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
spring.xml配置 数据库连接池使用德鲁伊,个人觉得各方面都是比较好的orm
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--<task:annotation-driven scheduler="myScheduler"/>-->
<!--<task:scheduler id="myScheduler" pool-size="5"/>-->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myTask"/>
<property name="targetMethod" value="execute"/>
<!-- false表示job不会并发执行,默认为true-->
<property name="concurrent" value="false"/>
</bean>
<bean id="doWork" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail" />
<property name="cronExpression" value="0 0 0 1 * ?" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="doWork"/>
</list>
</property>
</bean>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.www">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!-- 配置数据源 -->
<context:property-placeholder location="classpath:config/jdbc.properties"/>
<bean id="sourceParten" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 初始化连接数量 type:int -->
<property name="initialSize" value="${druid.initialSize}"/>
<!-- 最大并发数量 type:int -->
<property name="maxActive" value="${druid.maxActive}"/>
<!-- 最大空闲数量 type:int -->
<property name="maxIdle" value="10"/>
<!-- 最小空闲数量 type:int -->
<property name="minIdle" value="5"/>
<!-- 配置获取连接等待超时的时间,单位:毫秒 type:long -->
<property name="maxWait" value="10000"/>
<!-- 超过时间限制是否回收 type:boolean -->
<property name="removeAbandoned" value="true"/>
<!-- 上述回收超时时间 单位:秒 type:long -->
<property name="removeAbandonedTimeout" value="300000"/>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000"/>
<!-- 用来检测连接是否有效的sql,要求是一个查询语句 type:sql -->
<property name="validationQuery" value="select 1"/>
<!-- 申请连接的时候检测 type:boolean -->
<property name="testWhileIdle" value="true"/>
<!-- 申请连接时执行validationQuery检测连接是否有效,配置为true会降低性能 -->
<property name="testOnBorrow" value="false"/>
<!-- 归还连接时执行validationQuery检测连接是否有效,配置为true会降低性能 -->
<property name="testOnReturn" value="false"/>
<!-- 开启PSCache,并且指定每个连接上PSCache的大小 -->
<property name="poolPreparedStatements" value="false"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="-1"/>
<!--监控统计stat日志log4j 防御SQL注入wall -->
<property name="filters" value="stat,wall"/>
</bean>
<bean id="dataSource" parent="sourceParten" init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置 JPA 的 EntityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="database" value="MYSQL"/>
</bean>
</property>
<property name="packagesToScan" value="com.www.common.pojo"></property>
<property name="jpaProperties">
<props>
<prop key="hibernate.physical_naming_strategy">
<!--hibernate4 org.hibernate.cfg.ImprovedNamingStrategy -->
<!--hibernate5 org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl-->
<!-- 驼峰转下划线 -->
com.www.common.utils.ImprovedNamingStrategy
</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
<property name="sharedCacheMode" value="ENABLE_SELECTIVE"></property>
</bean>
<aop:config>
<aop:advisor pointcut="execution(* com.www.service.*.*(..))" advice-ref="txAdvice"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="login*" propagation="REQUIRED"/>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="bech*" propagation="REQUIRED"/>
<tx:method name="modify*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
<!-- 配置支持基于注解的事务 -->
<!-- <tx:annotation-driven transaction-manager="transactionManager"/> -->
<!-- 配置 SpringData -->
<jpa:repositories base-package="com.www.common.dao"/>
</beans>
spring-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-4.3.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.2.xsd">
<debug/>
<http pattern="/**/login.*" security="none"/>
<http pattern="/index.html" security="none"/>
<http pattern="/**/login_error.*" security="none"/>
<http pattern="/**/error.*" security="none"/>
<http pattern="/download/**" security="none"/>
<http pattern="/resources/**" security="none"/>
<http pattern="/upload/**" security="none"/>
<http pattern="/**/register.do" security="none"/>
<http pattern="/verify/**" security="none"/>
<http auto-config="false" use-expressions="true" entry-point-ref="loginEntryPoint">
<!-- 禁用CSRF保护,默认是启用 -->
<csrf disabled="true"/>
<headers disabled="true"/>
<anonymous enabled="false"/>
<!-- 基于角色认证(必须拥有ROLE_XXX角色才能访问所有/**/XXX/**资源) -->
<intercept-url pattern="/**/add*" access="hasRole('ADD')"/>
<intercept-url pattern="/**/update*" access="hasRole('UPDATE')"/>
<intercept-url pattern="/**/delete*" access="hasRole('DELETE')"/>
<intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/>
<intercept-url pattern="/seller/**" access="hasRole('SELLER')"/>
<intercept-url pattern="/user/**" access="hasRole('USER')"/>
<!--<intercept-url pattern="/**" access="authenticated"/>-->
<!--<remember-me remember-me-parameter="remember-me" data-source-ref="dataSource"/>-->
<!--<remember-me authentication-success-handler-ref="myAuthenticationSuccessHandler"/>-->
<logout logout-success-url="/login.do" logout-url="/loginout.do"/>
<!--如果concurrency-control标签配置了error-if-maximum-exceeded="true",max-sessions="1",那么第二次登录时,是登录不了的。-->
<!--如果error-if-maximum-exceeded="false",那么第二次是能够登录到系统的,-->
<!--但是第一个登录的账号再次发起请求时,会跳转到expired-url配置的url中,-->
<session-management invalid-session-url="/login.do" >
<concurrency-control max-sessions="1" error-if-maximum-exceeded="false" expired-url="/login.do"/>
</session-management>
<!-- 指定自己的权限验证过滤器,首先走自己的的过滤器 myFilter,如果被拦截就报没有权限;
如果通过会走spring security自带的拦截器,即上面配置的权限配置!-->
<custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER"/>
<custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="myFilter"/>
</http>
<!-- 登录页面 -->
<beans:bean id="loginEntryPoint" class="com.www.common.security.LoginEntryPoint">
<beans:constructor-arg name="loginFormUrl" value="/login.do"/>
</beans:bean>
<!--登录失败跳转页面,如需不使用页面返回可重写此类-->
<beans:bean id="loginFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login_error.do"/>
</beans:bean>
<!--登录成功跳转的页面-->
<beans:bean id="loginSuccessHandler" class="com.www.common.security.SuccessHandler">
<beans:property name="defaultTargetUrl" value="/index.do"/>
</beans:bean>
<beans:bean id="loginFilter" class="com.www.common.security.LoginFromFilter">
<!-- 登录提交处理 -->
<beans:property name="filterProcessesUrl" value="/shopping_login.do"/>
<!-- 登录成功跳转 -->
<beans:property name="authenticationSuccessHandler" ref="loginSuccessHandler"/>
<!-- 设置登录失败的网址 -->
<beans:property name="authenticationFailureHandler" ref="loginFailureHandler"/>
<!-- 用户拥有权限 -->
<beans:property name="authenticationManager" ref="authenticationManager"/>
<!--登录页面参数-->
<beans:property name="usernameParameter" value="username"/>
<beans:property name="passwordParameter" value="password"/>
<beans:property name="codeParameter" value="code"/>
</beans:bean>
<!-- 权限认证Spring日志监听器 -->
<beans:bean class="org.springframework.security.authentication.event.LoggerListener"/>
<beans:bean class="org.springframework.security.access.event.LoggerListener"/>
<beans:bean id="myFilter" class="com.www.common.security.SecurityInterceptor">
<!--登录验证-->
<beans:property name="authenticationManager" ref="authenticationManager"/>
<!--权限验证-->
<beans:property name="accessDecisionManager" ref="myAccessDecisionManagerBean"/>
<!--访问的url资源权限信息-->
<beans:property name="securityMetadataSource" ref="securityMetadataSource"/>
</beans:bean>
<!-- 验证配置,实现用户认证的入口,主要实现UserDetailsService接口即可 -->
<authentication-manager alias="authenticationManager">
<authentication-provider ref="myAuthenticationProvider"/>
</authentication-manager>
<!--用户登录验证配置和加密方式-->
<beans:bean id="myAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="myUserDetailService" />
<beans:property name="passwordEncoder" ref="passwordEncoder" />
</beans:bean>
<!-- spring推荐的单向加密算法 -->
<beans:bean id="passwordEncoder" class="com.www.common.utils.MD5"/>
<!-- 在这个类中,读入用户的密码,角色信息,是否锁定,账号是否过期等属性信息 -->
<beans:bean id="myUserDetailService" class="com.www.common.security.MyUserDetailService"/>
<!-- 访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 -->
<beans:bean id="myAccessDecisionManagerBean" class="com.www.common.security.DecisionManager"/>
<!-- 资源源数据定义,即定义某一资源可以被哪些角色访问 -->
<beans:bean id="securityMetadataSource" class="com.www.common.security.SecurityMetadataSource"/>
</beans:beans>
DecisionManager
package com.www.common.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 java.util.Collection;
import java.util.Iterator;
/**
* 访问决策器
* 决定某个用户具有的角色
* 是否有足够的权限去访问某个资源
* 在这种方法中,需要与configAttributes比较验证
* 1、一个对象是一个URL,一个过滤器被这个URL找到权限配置,并通过这里
* 2、如果没有匹配相应的认证,AccessDeniedException
* @author
*/
public class DecisionManager implements AccessDecisionManager {
private Logger log= LoggerFactory.getLogger(DecisionManager.class);
/**
* 在这个类中,最重要的是decide方法,如果不存在对该资源的定义,直接放行
* 否则,如果找到正确的角色,即认为拥有权限,并放行,
* 否则throw new AccessDeniedException("no right");
* 这样,就会进入上面提到的/accessDenied.jsp页面。
* @param authentication :当前用户所有的角色
* @param object :当前请求的URL
* @param configAttributes :当前URL所需要的角色
*/
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
// 资源所需的角色列表,如果角色列表为空,则放行!继续下一个拦截器。
if (configAttributes == null) {
return;
}
log.info("%%%%%authentication :"+authentication.toString());
log.info("&&&&&configAttributes :"+configAttributes.toString());
// 即将访问的资源URL,如 : /admin.jsp
log.info("URL :"+object);
// 遍历所需的角色集合
Iterator<ConfigAttribute> ite = configAttributes.iterator();
while (ite.hasNext()) {
ConfigAttribute ca = ite.next();
// 该资源所需要的角色
String needRole = ca.getAttribute();
// authentication.getAuthorities()获取用户所拥有的角色列表,如:OLE_DEFULT
for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
// 将资源所需要的角色与用户拥有的角色比较
if (needRole.equals(grantedAuthority.getAuthority())) {
// 角色相同,直接放行
return;
}
}
}
// 否则,提示没有权限访问该资源
throw new AccessDeniedException("no right");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
LoginEntryPoint 无权限时的登录页面
package com.www.common.security;
import com.www.common.enums.Constant;
import com.www.common.enums.RoleType;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.*;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.RedirectUrlBuilder;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 访问资源无权限时访问
* @Author: zhouchaoxi
* @Date: Created in 2018/7/7 0:13
* @Modified By:
*/
public class LoginEntryPoint implements AuthenticationEntryPoint,InitializingBean {
private PortMapper portMapper = new PortMapperImpl();
private PortResolver portResolver = new PortResolverImpl();
private String loginFormUrl;
private boolean forceHttps = false;
private boolean useForward = false;
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
public LoginEntryPoint(String loginFormUrl) {
Assert.notNull(loginFormUrl, "loginFormUrl cannot be null");
this.loginFormUrl = loginFormUrl;
}
/**
* Performs the redirect (or forward) to the login form URL.
*/
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
String redirectUrl = null;
String returnUrl = buildHttpReturnUrlForRequest(request);
System.out.println("========"+returnUrl+"========");
if (returnUrl.contains("/admin/")){
request.getSession().setAttribute(Constant.LOGIN_ROLE, RoleType.ADMIN());
this.loginFormUrl="/admin/login.do";
}else if(returnUrl.contains("/wap/")){
request.getSession().setAttribute(Constant.LOGIN_ROLE, RoleType.WAP());
this.loginFormUrl="/wap/login.do";
}else{
request.getSession().setAttribute(Constant.LOGIN_ROLE, RoleType.USER());
}
if (useForward) {
if (forceHttps && "http".equals(request.getScheme())) {
redirectUrl = buildHttpsRedirectUrlForRequest(request);
}
if (redirectUrl == null) {
String loginForm = determineUrlToUseForThisRequest(request, response, authException);
RequestDispatcher dispatcher = request.getRequestDispatcher(loginForm);
dispatcher.forward(request, response);
return;
}
} else {
redirectUrl = buildRedirectUrlToLoginPage(request, response, authException);
}
redirectStrategy.sendRedirect(request, response, redirectUrl);
}
protected String buildHttpReturnUrlForRequest(HttpServletRequest request) throws IOException, ServletException {
RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();
urlBuilder.setScheme("http");
urlBuilder.setServerName(request.getServerName());
urlBuilder.setPort(request.getServerPort());
urlBuilder.setContextPath(request.getContextPath());
urlBuilder.setServletPath(request.getServletPath());
urlBuilder.setPathInfo(request.getPathInfo());
urlBuilder.setQuery(request.getQueryString());
return urlBuilder.getUrl();
}
public void afterPropertiesSet() throws Exception {
Assert.isTrue(
StringUtils.hasText(loginFormUrl) && UrlUtils.isValidRedirectUrl(loginFormUrl),
"loginFormUrl must be specified and must be a valid redirect URL");
if (useForward && UrlUtils.isAbsoluteUrl(loginFormUrl)) {
throw new IllegalArgumentException("useForward must be false if using an absolute loginFormURL");
}
Assert.notNull(portMapper, "portMapper must be specified");
Assert.notNull(portResolver, "portResolver must be specified");
}
/**
* Allows subclasses to modify the login form URL that should be applicable for a
* given request.
*
* @param request the request
* @param response the response
* @param exception the exception
* @return the URL (cannot be null or empty; defaults to {@link #getLoginFormUrl()})
*/
protected String determineUrlToUseForThisRequest(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) {
return getLoginFormUrl();
}
protected String buildRedirectUrlToLoginPage(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
String loginForm = determineUrlToUseForThisRequest(request, response, authException);
if (UrlUtils.isAbsoluteUrl(loginForm)) {
return loginForm;
}
int serverPort = portResolver.getServerPort(request);
String scheme = request.getScheme();
RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();
urlBuilder.setScheme(scheme);
urlBuilder.setServerName(request.getServerName());
urlBuilder.setPort(serverPort);
urlBuilder.setContextPath(request.getContextPath());
urlBuilder.setPathInfo(loginForm);
if (forceHttps && "http".equals(scheme)) {
Integer httpsPort = portMapper.lookupHttpsPort(Integer.valueOf(serverPort));
if (httpsPort != null) {
// Overwrite scheme and port in the redirect URL
urlBuilder.setScheme("https");
urlBuilder.setPort(httpsPort.intValue());
}
else {
}
}
return urlBuilder.getUrl();
}
/**
* Builds a URL to redirect the supplied request to HTTPS. Used to redirect the
* current request to HTTPS, before doing a forward to the login page.
*/
protected String buildHttpsRedirectUrlForRequest(HttpServletRequest request) throws IOException, ServletException {
int serverPort = portResolver.getServerPort(request);
Integer httpsPort = portMapper.lookupHttpsPort(Integer.valueOf(serverPort));
if (httpsPort != null) {
RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();
urlBuilder.setScheme("https");
urlBuilder.setServerName(request.getServerName());
urlBuilder.setPort(httpsPort.intValue());
urlBuilder.setContextPath(request.getContextPath());
urlBuilder.setServletPath(request.getServletPath());
urlBuilder.setPathInfo(request.getPathInfo());
urlBuilder.setQuery(request.getQueryString());
return urlBuilder.getUrl();
}
return null;
}
/**
* Set to true to force login form access to be via https. If this value is true (the
* default is false), and the incoming request for the protected resource which
* triggered the interceptor was not already <code>https</code>, then the client will
* first be redirected to an https URL, even if <tt>serverSideRedirect</tt> is set to
* <tt>true</tt>.
*/
public void setForceHttps(boolean forceHttps) {
this.forceHttps = forceHttps;
}
protected boolean isForceHttps() {
return forceHttps;
}
public String getLoginFormUrl() {
return loginFormUrl;
}
public void setPortMapper(PortMapper portMapper) {
Assert.notNull(portMapper, "portMapper cannot be null");
this.portMapper = portMapper;
}
protected PortMapper getPortMapper() {
return portMapper;
}
public void setPortResolver(PortResolver portResolver) {
Assert.notNull(portResolver, "portResolver cannot be null");
this.portResolver = portResolver;
}
protected PortResolver getPortResolver() {
return portResolver;
}
/**
* Tells if we are to do a forward to the {@code loginFormUrl} using the
* {@code RequestDispatcher}, instead of a 302 redirect.
*
* @param useForward true if a forward to the login page should be used. Must be false
* (the default) if {@code loginFormUrl} is set to an absolute value.
*/
public void setUseForward(boolean useForward) {
this.useForward = useForward;
}
protected boolean isUseForward() {
return useForward;
}
}
LoginFormFilter 登录验证类,登录验证之前执行,可以在这里加入验证码、登录角色之类的验证,验证失败直接抛出异常就OK