Spring security implements the permission management example
- 2020-05-30 20:15:58
- OfStack
Spring security implements an example of permission management, as follows:
1. Configuration files
1, 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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.nercita</groupId>
<artifactId>BCP</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>BCP</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.0.5.RELEASE</spring.version>
<spring.security.version>3.2.3.RELEASE</spring.security.version>
<hibernate.version>4.3.5.Final</hibernate.version>
</properties>
<dependencies>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.annotation</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.ejb</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-osgi-bundle</artifactId>
<version>1.0.1-SP3</version>
<exclusions>
<exclusion>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.servlet</artifactId>
<version>3.0.1</version>
</dependency>
<!-- spring4 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</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-context-support</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-beans</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-expression</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-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</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-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring mvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc-portlet</artifactId>
<version>${spring.version}</version>
</dependency>
-->
<!-- spring security -->
<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-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<!-- aspectj weaver.jar This is a SpringAOP The dependency package to be used -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.2</version>
</dependency>
<!-- Database driven -mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
<!-- Database driven -oracle -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>12.1.0.1</version>
</dependency>
<!-- Database connection pool -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5</version>
</dependency>
<!-- hibernate4 Core and dependency packages -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
<exclusions>
<exclusion>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</exclusion>
<exclusion>
<artifactId>c3p0</artifactId>
<groupId>c3p0</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- support JPA Specification of the core The facade -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
<exclusions>
<exclusion>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- JPA Implementation of annotations -->
<!--
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.1.Final</version>
</dependency>
-->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<!-- In order to make Hibernate Using the proxy pattern, yes javassist -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.18.1-GA</version>
</dependency>
<!-- antlr -->
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>2.7.7</version>
</dependency>
<!-- dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!-- apache commons -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.0</version>
</dependency>
<!-- pinyin4j -->
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>2.5.0</version>
</dependency>
<!-- Other mandatory dependent packages -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--ehcache The cache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.8.3</version>
</dependency>
<!-- Other components -->
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>spring-osgi-annotation</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.3</version>
</dependency>
<!----> <dependency>
<groupId>org.apache</groupId>
<artifactId>cxf</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.sitemesh</groupId>
<artifactId>sitemesh</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.1.7</version>
<exclusions>
<exclusion>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.3.0.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml</groupId>
<artifactId>classmate</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.7</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.3.12</version>
<exclusions>
<exclusion>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>2.3.12</version>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.4.7</version>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.2</version>
</dependency>
<dependency>
<groupId>org.apache.ws.commons.schema</groupId>
<artifactId>XmlSchema</artifactId>
<version>1.4.7</version>
</dependency>
<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.2.1</version>
</dependency>
<!-- log4j The log -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- slf4j-api Log interface -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<!-- slf4j-log4j12 Log interface bridge -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.7</version>
</dependency>
<!-- slf4j-nop The log -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.7</version>
</dependency>
<!-- log4j2 The log -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.1</version>
</dependency>
<!-- File upload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- fastJson json array-related -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.1</version>
</dependency>
<!-- use Jackson the Java Object conversion to JSON string -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<!-- poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.13</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.13</version>
</dependency>
<!--
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>openxml4j</artifactId>
<version>1.0-beta</version>
</dependency>
-->
<!-- jxls -->
<dependency>
<groupId>net.sf.jxls</groupId>
<artifactId>jxls-core</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>net.sf.jxls</groupId>
<artifactId>jxls-reader</artifactId>
<version>1.0.6</version>
</dependency>
<!-- xmlpull xml to java -->
<dependency>
<groupId>xmlpull</groupId>
<artifactId>xmlpull</artifactId>
<version>1.1.3.4a</version>
</dependency>
<!-- use JSONObject, Converts the received result into JSON format -->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier><!-- The specified jdk version -->
</dependency>
<!-- net.sf.json-lib Packages depend on the following packages :-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>net.sf.ezmorph</groupId>
<artifactId>ezmorph</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.7</version>
</dependency>
<!-- Cloud communication SMS send API-->
<dependency>
<groupId>com.yuntongxun</groupId>
<artifactId>ccp</artifactId>
<version>2.6.3</version>
</dependency>
</dependencies>
<build>
<finalName>BCP</finalName>
</build>
</project>
2.web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>SSH-Application</display-name>
<!-- Initialization parameter -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext*.xml</param-value>
</context-param>
<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
<param-value>message/message-info</param-value>
</context-param>
<!--Spring ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- ETag The filter , Save bandwidth -->
<filter>
<filter-name>etagFilter</filter-name>
<filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>etagFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--UTF-8 coding -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- OpenSessionInViewFilter -->
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<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>
<!-- Page assembly -sitemesh -->
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>org.sitemesh.config.ConfigurableSiteMeshFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Clean up the memory -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<!-- WebService-CXF -->
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<!-- spring-MVC -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- session The expiration time -->
<session-config>
<session-timeout>60</session-timeout>
</session-config>
<!-- The default home page -->
<welcome-file-list>
<welcome-file>/main.jsp</welcome-file>
</welcome-file-list>
<!-- Abnormal page -->
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/common/500.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/common/500.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/common/404.jsp</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/common/403.jsp</location>
</error-page>
<!--
<servlet>
<servlet-name>coreServlet</servlet-name>
<servlet-class>
org.nercita.bcp.wechat.servlet.CoreServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>coreServlet</servlet-name>
<url-pattern>/wx.do</url-pattern>
</servlet-mapping>
-->
</web-app>
3.application-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.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<!-- Configure static resources such as images that do not filter -->
<http pattern="/services*" security="none" />
<http pattern="/wx.do*" security="none" />
<http pattern="/api/**" security="none" />
<http pattern="/services/**" security="none" />
<http pattern="/common/**" security="none" />
<http pattern="/images/**" security="none" />
<http pattern="/styles/**" security="none" />
<http pattern="/js/**" security="none" />
<http pattern="/css/**" security="none" />
<http pattern="/htm/**" security="none" />
<http pattern="/main.jsp*" security="none" />
<http pattern="/login.jsp*" security="none" />
<http pattern="/install.jsp*" security="none" />
<http pattern="/system/springSecurity/init*" security="none" />
<http pattern="/system/user/registPage*" security="none" />
<http pattern="/system/user/regist*" security="none" />
<http pattern="/mr*" security="none" />
<http pattern="/system/user/mobile/regist*" security="none" />
<http pattern="/system/user/activate*" security="none" />
<http pattern="/system/user/checkImg*" security="none" />
<http pattern="/system/user/checkName*" security="none" />
<http pattern="/system/user/checkValidateCode*" security="none" />
<http pattern="/system/user/forgotPassword*" security="none" />
<http pattern="/system/user/resetRequest*" security="none" />
<http pattern="/system/user/resetPasswordPage*" security="none" />
<http pattern="/system/user/resetPassword*" security="none" />
<http pattern="/system/message/save*" security="none" />
<http pattern="/system/message/introduction" security="none" />
<http auto-config="true" create-session="always" access-denied-page="/common/403.jsp"
use-expressions="true" disable-url-rewriting="true">
<!-- Configure the login page -->
<form-login login-page="/login.jsp" login-processing-url="/j_spring_security_check"
authentication-failure-url="/login.jsp?error=true"
default-target-url="/index"
always-use-default-target="true"
authentication-success-handler-ref="authenticationSuccess"
authentication-failure-handler-ref="exceptionMappingAuthenticationFailureHandler"/>
<!-- " Remember that I " Function, using persistence strategy ( Store the user's login information cookie -->
<remember-me key="bcp" use-secure-cookie="true" />
<!-- User exits the jump page -->
<!-- <logout invalidate-session="true" logout-url="/j_spring_security_logout" logout-success-url="/login.jsp"/> -->
<logout invalidate-session="true" logout-url="/j_spring_security_logout" success-handler-ref="logoutSuccessHandler" />
<!-- Session management, set the maximum login exception, error-if-maximum-exceeded = false For the first 2 The first login will make the previous 1 Individual logon failure -->
<session-management invalid-session-url="/login.jsp?expired=true">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="false" expired-url="/login.jsp?expired=true"/>
</session-management>
<!-- Add custom filters On the FILTER_SECURITY_INTERCEPTOR Before effective -->
<custom-filter ref="customFilterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" />
<custom-filter ref="switchUserProcessingFilter" after="FILTER_SECURITY_INTERCEPTOR"/>
<anonymous enabled="false" />
</http>
<!-- Login jump -->
<beans:bean id="authenticationSuccess" class="org.nercita.bcp.system.service.CustomSavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/index"/>
</beans:bean>
<!-- Cancellation of success -->
<beans:bean id="logoutSuccessHandler" class="org.nercita.bcp.system.service.CustomLogoutSuccessHandler">
<beans:property name="defaultTargetUrl" value="/login.jsp"></beans:property>
</beans:bean>
<beans:bean id="customUserDetailsService" class="org.nercita.bcp.system.service.CustomUserDetailsService"/>
<!-- User login processing -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder hash="md5" base64="true" >
<salt-source user-property="username"/>
</password-encoder>
</authentication-provider>
</authentication-manager>
<beans:bean id="exceptionMappingAuthenticationFailureHandler" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
<beans:property name="exceptionMappings">
<beans:props>
<beans:prop key="org.springframework.security.authentication.DisabledException">/login.jsp?role=false</beans:prop>
<beans:prop key="org.springframework.security.authentication.BadCredentialsException">/login.jsp?error=true</beans:prop>
<beans:prop key="org.springframework.security.authentication.LockedException">/login.jsp?locked=true</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<beans:bean id="switchUserProcessingFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserFilter">
<beans:property name="userDetailsService" ref="customUserDetailsService" />
<beans:property name="switchUserUrl" value="/j_spring_security_switch_user" />
<beans:property name="exitUserUrl" value="/j_spring_security_exit_user" />
<beans:property name="targetUrl" value="/index" />
</beans:bean>
</beans:beans>
4. applicationContext.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- Import properties file -->
<context:property-placeholder location="classpath*:/application.properties" />
<context:spring-configured />
<!-- annotations bean And dependency injection -->
<context:component-scan base-package="org.nercita.bcp">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation" />
</context:component-scan>
<!-- The data source -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${db.driverClass}"/>
<property name="jdbcUrl" value="${db.url}"/>
<property name="user" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<!-- sessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.cache.use_second_level_cache">${hibernate.use_second_level_cache}</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.use_query_cache}</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl}</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>org.nercita.bcp.**.domain**</value>
</list>
</property>
</bean>
<!-- Transaction manager -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- Open annotation transaction -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- To obtain spring context the ApplicationContextAware The implementation of the Bean -->
<bean class="org.nercita.core.utils.SpringContextHolder" lazy-init="false" />
</beans>
5.application.properties
#jdbc settings
#Mysql settings 3306
#db.url=jdbc:mysql://localhost:3306/bcp
#db.driverClass=com.mysql.jdbc.Driver
#db.username=root
#db.password=0729
#hibernate.dialect=org.hibernate.dialect.MySQLDialect
#hibernate settings
hibernate.show_sql=true
hibernate.format_sql=true
hibernate.use_second_level_cache=true
hibernate.use_query_cache=true
hibernate.hbm2ddl=update
6. springMVC-config.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" 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.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- Static resource Don't intercept -->
<mvc:resources location="/common/" mapping="/common/**"/>
<mvc:resources location="/images/" mapping="/images/**" />
<mvc:resources location="/js/" mapping="/js/**" />
<mvc:resources location="/css/" mapping="/css/**" />
<mvc:resources location="/styles/" mapping="/styles/**" />
<mvc:resources location="/htm/" mapping="/htm/**" />
<import resource="view-controller.xml" />
<context:annotation-config/>
<context:component-scan base-package="org.nercita.bcp" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation" />
</context:component-scan>
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.nercita.core.web.springmvc.StringHttpMessageConverter" />
<ref bean="msgConverter"/>
</list>
</property>
<property name="webBindingInitializer">
<bean class="org.nercita.core.web.springmvc.CustomBindInitializer">
<!--
<property name="validator" ref="validator" />
<property name="conversionService" ref="conversionService" />
-->
</bean>
</property>
</bean>
<bean id="msgConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>text/json;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
<!--
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"/>
-->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="ignoreAcceptHeader" value="true"/>
<property name="defaultContentType" value="text/html"/>
<property name="mediaTypes">
<map>
<entry key="json" value="application/json"/>
<entry key="xml" value="application/xml"/>
</map>
</property>
<property name="favorParameter" value="false"/>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller">
<bean class="org.springframework.oxm.xstream.XStreamMarshaller"/>
</property>
</bean>
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView" value="error" />
<property name="exceptionMappings">
<props>
<prop key=".DataAccessException">dataAccessFailure</prop>
<prop key=".NoSuchRequestHandlingMethodException">resourceNotFound</prop>
<prop key=".TypeMismatchException">resourceNotFound</prop>
<prop key=".lang.Exception">uncaughtException</prop>
</props>
</property>
</bean>
<!-- File upload -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="104857600"/>
<property name="maxInMemorySize" value="4096"/>
</bean>
<!-- Process internationalized resource files -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="message/message-info" />
<property name="useCodeAsDefaultMessage" value="true" />
</bean>
</beans>
2. Implementation code
1, CustomAccessDecisionManager. Java
package org.nercita.bcp.system.service;
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;
import org.springframework.stereotype.Service;
/**
* This class is the access decision-maker, which determines whether a user has a role and has enough permission to access a resource, so as to realize the corresponding relation between user and access permission.
* This class deals primarily with users accessing a particular URL By comparing the permissions to access the class with those of the logged-in user,
* If the user has permission, they can access the resource, if they don't have permission, they can't access the resource, and they throw it 1 An exception.
* AccessdecisionManager in Spring security Chinese is very important.
* The validation section briefly covers all of them Authentication The implementation needs to be saved in 1 a GrantedAuthority In an array of objects. This is the authority granted to the principal.
* GrantedAuthority Object through AuthenticationManager Save to Authentication In the object, and then from AccessDecisionManager Read it out and make an authorization judgment.
* Spring Security provides 1 Interceptors that control access to secure objects, such as method calls or web The request.
* 1 Whether or not precalling is allowed is determined by AccessDecisionManager The implementation.
* this AccessDecisionManager be AbstractSecurityInterceptor The call, Used to make final access control decisions.
*
* this AccessDecisionManager Interface includes 3 Methods:
* void decide(Authentication authentication, Object secureObject, List<ConfigAttributeDefinition> config);
* boolean supports(ConfigAttribute attribute); boolean supports(Class clazz);
* The first 1 Methods: AccessDecisionManager Pass all the information using the method parameters and make the decision during the authentication evaluation.
* If access is denied, the implementation throws it 1 a AccessDeniedException The exception.
* The first 2 Method: be at startup time AbstractSecurityInterceptor The call,
* To determine the AccessDecisionManager Whether the delivery can be performed ConfigAttribute .
* The first 3 Methods: called by the security interceptor implementation, The security interceptor will be displayed AccessDecisionManager Types of security objects are supported.
*/
@Service("customAccessDecisionManager")
public class CustomAccessDecisionManager implements AccessDecisionManager {
/**
* This method: requires a comparison of permissions and permissions configuration
* object The parameter is 1 a URL, with 1 Each filter should url The corresponding permission configuration is passed .
* To view authentication Whether there are permissions in configAttributes In the
* If there are no matching permissions , Throw it out 1 Access denied exceptions
*/
@Override
public void decide(Authentication authentication, Object object,
Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
if (configAttributes==null){
return;
}
Iterator<ConfigAttribute> iter = configAttributes.iterator();
while(iter.hasNext()){
ConfigAttribute ca = iter.next();
String needRole = ((SecurityConfig) ca).getAttribute();
//gra Is the permission granted to the user, needRole The permissions you should have to access the appropriate resources
for (GrantedAuthority gra : authentication.getAuthorities()) {
if (needRole.trim().equals(gra.getAuthority().trim())) {
return;
}
}
}
throw new AccessDeniedException("Access Denied");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
2, CustomFilterInvocationSecurityMetadataSource java
package org.nercita.bcp.system.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.annotation.PostConstruct;
import org.nercita.bcp.system.domain.Authority;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;
/**
* This class is the definition of access rights for resources and implements the corresponding relationship between resources and access rights
* The main function of this class is in Spring Security After the entire filter chain is started,
* When the container starts, the program enters the class init() Method, init Call the loadResourceDefine() Method,
* The main purpose of this method is to save all the resources and permissions in the database to the local cache!
* In the class resourceMap It's a collection of all the resources and permissions that you save, URL for Key , permission as Value !
*
* @author zhangwenchao
*
*/
@Service("customFilterInvocationSecurityMetadataSource")
public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
@Autowired
private AuthorityService authorityService;
// Using the AntUrlPathMatcher this path matcher To check the URL Matches the resource definition
//private RequestMatcher urlMatcher = null;
//resourceMap It's a collection of all the resources and permissions that you save, URL for Key , permission as Value !
private static HashMap<String, Collection<ConfigAttribute>> resourceMap = null;
/**
*
* Custom methods that this class puts in Spring After the container,
* The specified init To initialize the method, read the resource from the database
*/
@PostConstruct
public void init() {
loadResourceDefine();
}
/**
*
* All resource information is loaded when the program starts
* Initializes the mapping between resources and permissions
*/
private void loadResourceDefine() {
// in Web When the server starts, extract all permissions from the system authority.name.
List<Authority> authorities = authorityService.findAll();
// Should be resource for key . Permissions for value . Resources are usually url . Permissions are those ROLE_ Is a prefixed role. 1 Resources can be accessed by multiple permissions.
resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
if(authorities!=null && authorities.size()>0 )
for (Authority auth : authorities) {
String authName = auth.getCode(); // privileged name Based on ROLE_ Is the code value of the prefix
ConfigAttribute ca = new SecurityConfig(authName); // will ROLE_XXX Encapsulated into spring Permission configuration properties
// Gets all the resources by the permission name
String url = auth.getResourceUrl();
// Determine the relationship between the resource file and the permissions, if the relevant resources already exist url , then pass the url for key Extract the permission set and add the permissions to the permission set.
if (resourceMap.containsKey(url)) { // If it exists url Join the permissions
Collection<ConfigAttribute> value = resourceMap.get(url);
value.add(ca);
resourceMap.put(url, value);
} else {// If it doesn't exist url join url And permissions
Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
atts.add(ca);
resourceMap.put(url, atts);
}
}
}
/**
* According to the URL To get the URL Configuration of permissions
*/
@Override
public Collection<ConfigAttribute> getAttributes(Object object)
throws IllegalArgumentException {
//object is 1 a URL , Request for user URL
String url = ((FilterInvocation)object).getRequestUrl();
int firstQuestionMarkIndex = url.indexOf("?");
if (firstQuestionMarkIndex != -1) {
url = url.substring(0, firstQuestionMarkIndex);
}
Iterator<String> iter = resourceMap.keySet().iterator();
String matchUrl=null;// matching url
// Get the requested URL Then compare it with the resources extracted above
while (iter.hasNext()) {
String resURL = iter.next();
// if(urlMatcher.pathMatchesUrl(resURL,url)){
if(url.startsWith(resURL)){
// return resourceMap.get(resURL); // Returns a collection of permissions
// An initial or current match url Longer updates match url
if(matchUrl==null||matchUrl.length()<resURL.length())
matchUrl=resURL;
}
}
if(matchUrl!=null){
// If there is a match url Returns the required permissions
// System.out.println(matchUrl+"-------"+resourceMap.get(matchUrl));
return resourceMap.get(matchUrl);
}
// When there are no resource permissions in the system url , the user in the case of access to this resource, return null Said release .
// If and when the system allocates resources url, But the user's role does not The user is not authorized to access this page
return null;
}
/*
* @return
* @link org.springframework.security.access.SecurityMetadataSource#getAllConfigAttributes()
*/
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
3, CustomFilterSecurityInterceptor java
package org.nercita.bcp.system.service;
import java.io.IOException;
import javax.annotation.Resource;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.nercita.bcp.system.util.LogInfoService;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;
@Service("customFilterSecurityInterceptor")
public class CustomFilterSecurityInterceptor extends
AbstractSecurityInterceptor implements Filter {
// Inject the resource data definer
@Resource
@Qualifier("customFilterInvocationSecurityMetadataSource")
private FilterInvocationSecurityMetadataSource securityMetadataSource;
// Inject the access decision-maker
@Resource
@Qualifier("customAccessDecisionManager")
@Override
public void setAccessDecisionManager(AccessDecisionManager accessDecisionManager){
super.setAccessDecisionManager(accessDecisionManager);
}
// Inject the authentication manager
@Resource
@Qualifier("authenticationManager")
@Override
public void setAuthenticationManager(AuthenticationManager newManager) {
super.setAuthenticationManager(newManager);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest)request;
HttpServletResponse httpResponse = (HttpServletResponse)response;
// The user is not logged in By entering a valid one in the address bar url Access to the system May cause system problems, so restrict anonymous user logins Automatically jumps to the login page
if(LogInfoService.getLoginUserName()==null){
httpResponse.sendRedirect(httpRequest.getContextPath()+"/login.jsp");
return;
}
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
/**
*
* @param fi
* @throws ServletException
* @throws IOException
*/
private 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);
// }
InterceptorStatusToken token = null;
try {
token = super.beforeInvocation(fi);
} catch (Exception e) {
// When the user logs in Resources that are accessed by users exist in the system url And permission, but not in the current user's role So the prompt redirects to a page that the user has no access to
if( e instanceof AccessDeniedException){
// HttpServletRequest httpRequest = fi.getRequest();
// HttpServletResponse httpResponse = fi.getResponse();
//
// String path = httpRequest.getContextPath();
// String basePath = httpRequest.getScheme()+"://"+httpRequest.getServerName()+":"+httpRequest.getServerPort()+path+"/";
// httpResponse.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
// RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(basePath+"/common/403.jsp");
//
// dispatcher.forward(httpRequest, httpResponse);
// httpResponse.sendRedirect(basePath+"/common/403.jsp");
throw new AccessDeniedException(" Users have no access ");
}
return;
}
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
super.afterInvocation(token, null);
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
@Override
public Class<? extends Object> getSecureObjectClass() {
return FilterInvocation.class;
}
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}
@Override
public void destroy() {
}
public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return securityMetadataSource;
}
public void setSecurityMetadataSource(
FilterInvocationSecurityMetadataSource securityMetadataSource) {
this.securityMetadataSource = securityMetadataSource;
}
}
3. Core processing: CustomUserDetailsService.java
package org.nercita.bcp.system.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.annotation.Resource;
import org.nercita.bcp.system.dao.AuthorityDao;
import org.nercita.bcp.system.dao.UserDao;
import org.nercita.bcp.system.domain.Authority;
import org.nercita.bcp.system.domain.User;
import org.nercita.bcp.system.domain.reference.UserDetail;
import org.nercita.bcp.system.domain.reference.UserState;
import org.nercita.bcp.system.domain.reference.UserType;
import org.springframework.dao.DataAccessException;
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 org.springframework.stereotype.Service;
/**
* This class is the definition and validation of user information
* This class deals with the user's login information. After the user enters his/her username and password,
* spring security It calls the inside of the class with the user name loadUserByUsername(usrename) Method,
* Look up the user information by the user name, and then store the user password found in the database and the user just entered in session The password in the comparison, and then determine whether the user is legal!
*
*/
@Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
// User persistence class
@Resource(name="userDao")
private UserDao userDao;
@Resource(name="authorityDao")
private AuthorityDao authorityDao;
@Override
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException, DataAccessException {
// Get the login user according to the login name
User user = userDao.findByName(userName);
if(null == user) {
throw new UsernameNotFoundException(" The user " + userName + " There is no ");
}
// According to the user's