Spring mvc+Spring Security integration, and the solution to the 404 problem in j_spring_security_check

 
This article uses Spring 3.2.18.Release version, Spring Security uses 2.0.5.RELEASE, and this article uses xml to configure Spring Security
The pom file is as follows: 
<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.0http://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.koolyun</groupId>
     <artifactId>Mcht-Service-Client</artifactId>
     <packaging>war</packaging>
     <version>0.0.1-SNAPSHOT</version>
     <name>Mcht-Service-Client Maven Webapp</name>
     <url>http://maven.apache.org</url>
     <properties>
          <!-- spring版本号 -->
          <spring.version>3.2.18.RELEASE</spring.version>
          <!-- 3.0.3.RELEASE< -->
          <log4j.version>1.2.17</log4j.version>
          <!-- mybatis版本号 -->
          <mybatis.version>3.3.0</mybatis.version>
     </properties>
     <dependencies>
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>3.8.1</version>
              <scope>test</scope>
          </dependency>
           <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
        </dependency>
          <dependency>
              <groupId>commons-logging</groupId>
              <artifactId>commons-logging</artifactId>
              <version>1.2</version>
          </dependency>
          
          <dependency>
              <groupId>commons-lang</groupId>
              <artifactId>commons-lang</artifactId>
              <version>2.6</version>
          </dependency>
          
          <!-- spring核心包 -->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-core</artifactId>
              <version>${spring.version}</version>
              <exclusions>
                   <exclusion>
                        <groupId>commons-logging</groupId>
                        <artifactId>commons-logging</artifactId>
                   </exclusion>
              </exclusions>
          </dependency>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-web</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-tx</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-webmvc</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-support</artifactId>
              <version>${spring.version}</version>
          </dependency>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-test</artifactId>
              <version>${spring.version}</version>
          </dependency>
     <!-- spring security start -->
          <dependency>
              <groupId>org.springframework.security</groupId>
              <artifactId>spring-security-acl</artifactId>
              <version>2.0.5.RELEASE</version>
          </dependency>
          <dependency>
              <groupId>org.springframework.security</groupId>
              <artifactId>spring-security-core</artifactId>
              <version>2.0.5.RELEASE</version>
          </dependency>
          <dependency>
              <groupId>org.springframework.security</groupId>
              <artifactId>spring-security-core-tiger</artifactId>
              <version>2.0.5.RELEASE</version>
          </dependency>
          <dependency>
              <groupId>org.springframework.security</groupId>
              <artifactId>spring-security-taglibs</artifactId>
              <version>2.0.5.RELEASE</version>
          </dependency>
          <!-- 日志文件管理包 -->
          <!-- log start -->
          <dependency>
              <groupId>log4j</groupId>
              <artifactId>log4j</artifactId>
              <version>${log4j.version}</version>
          </dependency>
          
          <dependency>
              <groupId>javax.servlet</groupId>
              <artifactId>servlet-api</artifactId>
              <version>2.5</version>
          </dependency>
          <dependency>
              <groupId>net.sf.ezmorph</groupId>
              <artifactId>ezmorph</artifactId>
              <version>1.0.6</version>
          </dependency>
          <dependency>
              <groupId>net.sf.json-lib</groupId>
              <artifactId>json-lib</artifactId>
              <version>2.4</version>
              <classifier>jdk15</classifier>
          </dependency>
          <!-- 映入JSON -->
          <dependency>
              <groupId>org.codehaus.jackson</groupId>
              <artifactId>jackson-mapper-asl</artifactId>
              <version>1.9.13</version>
          </dependency>
          <!-- funee -->
          <dependency>
              <groupId>org.funee.framework</groupId>
              <artifactId>funee</artifactId>
              <version>1.0.0</version>
          </dependency>
          <!-- https://mvnrepository.com/artifact/commons-pool/commons-pool -->
          <dependency>
              <groupId>commons-pool</groupId>
              <artifactId>commons-pool</artifactId>
              <version>1.6</version>
          </dependency>
     </dependencies>
     <build>
          <finalName>Mcht-Service-Client</finalName>
          
          <pluginManagement>
              <plugins>
                   <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-compiler-plugin</artifactId>
                         <configuration>
                             <source>1.7</source>
                             <target>1.7</target>
                         </configuration>
                   </plugin>
                   <plugin>
                        <groupId>org.apache.tomcat.maven</groupId>
                        <artifactId>tomcat7-maven-plugin</artifactId>
                        <configuration>
                             <port>8080</port>
                             <path>/</path>
                        </configuration>
                   </plugin>
              </plugins>
          </pluginManagement>
          
     </build>
</project>

There is a point in this, I use web.xml to intercept .do requests. This also lays a pit for the subsequent configuration of Spring to intercept login requests.

Spring intercepts the /j_spring_security_check request by default. In principle, you only need to configure the from action as /j_spring_security_check in the form of the page to enter the Spring Security processing flow when logging in. However, because only .do requests are configured, so this It needs to be configured in the xml of spring_security: login-processing-url="/j_spring_security_check.do", and the logou request also needs to be specified separately: <s:logout logout-success-url="/login/index.do" logout -url="/j_spring_security_logout.do"/>

If you do not specify the .do format, /j_spring_security_check and /j_spring_security_logout will return 404
 
 
First introduce the spring-security xml file in web.xml
 
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_1515646461031" version="3.0">
  <display-name>Archetype Created Web Application</display-name>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-mybatis.xml,classpath:spring-security.xml</param-value>
  </context-param>
  <filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <async-supported>true</async-supported>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <listener>
    <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
  </listener>
  <context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>classpath:log4j.properties</param-value>
  </context-param>
  <context-param>
    <param-name>log4jRefreshInterval</param-name>
    <param-value>6000</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
  </listener>
  <servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>com.koolyun.common.utils.UriScanDispatchServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
  </servlet>
  <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.gif</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.png</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.swf</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.woff</url-pattern>
  </servlet-mapping>
    <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.ttf</url-pattern>
  </servlet-mapping>
    <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.ico</url-pattern>
  </servlet-mapping>
    <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.woff2</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>
  <context-param>
    <param-name>webAppRoot</param-name>
    <param-value>lightnote.root</param-value>
  </context-param>
  <welcome-file-list>
    <welcome-file>/login.jsp</welcome-file>
  </welcome-file-list>
<!--   <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>
   -->
 
  <!-- Spring Security JCaptcha filter -->
       <filter>
              <filter-name>jcaptchaFilter</filter-name>
              <filter-class>com.koolyun.security.service.impl.JCaptchaFilter</filter-class>
              <init-param>
                     <param-name>failureUrl</param-name>
                     <param-value>/login/error.do?error=1</param-value>
              </init-param>
       </filter>
       <!-- jcaptcha图片生成URL. -->
       <filter-mapping>
              <filter-name>jcaptchaFilter</filter-name>
              <url-pattern>/commons/jcaptcha.jpg</url-pattern>
       </filter-mapping>
       <!-- jcaptcha登录表单处理URL.
                    必须放在springSecurityFilter的filter-mapping定义之前 -->
        <filter-mapping>
              <filter-name>jcaptchaFilter</filter-name>
              <url-pattern>/j_spring_security_check.do</url-pattern>
       </filter-mapping>
       <!--Spring Security 2-->
    <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>
</web-app>

 


 

The form-login attribute is explained in detail as follows:

form-login is a tag for configuring login-related information in the spring security namespace, and it contains the following attributes:

1. login-page custom login page url, the default is /login

2. login-processing-url The url intercepted by the login request, that is, the action specified when the form is submitted

3. default-target-url is the default URL to redirect after successful login

4. Always-use-default-target Whether to always use the default redirect url after successful login

5. authentication-failure-url URL redirected after login failure

6. The request field of username-parameter username defaults to userName

7. The password-parameter password request field defaults to password

8. authentication-success-handler-ref points to an AuthenticationSuccessHandler for handling successful authentication requests, and cannot be used at the same time as default-target-url and always-use-default-target

9. authentication-success-forward-url 用于authentication-failure-handler-ref

10. authentication-failure-handler-ref points to an AuthenticationFailureHandler for handling failed authentication requests

11. authentication-failure-forward-url 用于authentication-failure-handler-ref

12. authentication-details-source-ref points to an AuthenticationDetailsSource, used in the authentication filter


The following is the spring_security, xml file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:s="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/securityhttp://www.springframework.org/schema/security/spring-security-2.0.4.xsd"
       default-autowire="byType">
       <description>SpringSecurity安全配置</description>
       <!-- http安全配置 -->
       <s:http auto-config="true" access-decision-manager-ref="accessDecisionManager"
              access-denied-page="/commons/403.jsp">
              <s:intercept-url pattern="/commons/**" filters="none" />
              <s:intercept-url pattern="/images/**" filters="none" />
              <s:intercept-url pattern="/saas/**" filters="none" />
              <s:intercept-url pattern="/scripts/**" filters="none" />
              <s:intercept-url pattern="/assets/**" filters="none" />
              <s:intercept-url pattern="/styles/**" filters="none" />
              <s:intercept-url pattern="/widgets/**" filters="none" />
              <!-- <s:intercept-url pattern="/api/**" filters="none" />  -->
              <s:intercept-url pattern="/mobile/**" filters="none" />
              <s:intercept-url pattern="/wx-download/**" filters="none" />
              <s:intercept-url pattern="/coupon/c/**" filters="none" />
              <s:intercept-url pattern="/coupon/mm/**" filters="none" />
              <s:intercept-url pattern="/koolcoupon/**" filters="none" />
              <s:intercept-url pattern="/pay/Notify/**" filters="none" />
              <!--<s:intercept-url pattern="/pay/NotifyTest/**" filters="none" />-->
              <s:form-login login-page="/login/index.do" login-processing-url="/j_spring_security_check.do"  authentication-failure-url="/login/error.do?error=true" default-target-url="/login/target.do" always-use-default-target="true" />
              <s:logout logout-success-url="/login/index.do" logout-url="/j_spring_security_logout.do"/>
              <s:concurrent-session-control expired-url="/login/sessionExpired.do"  />
       </s:http>
       <!-- 认证配置 -->
       <s:authentication-provider user-service-ref="userDetailsService">
              <!-- 可设置hash使用sha1或md5散列密码后再存入数据库 -->
              <s:password-encoder hash="md5" />
       </s:authentication-provider>
       <!-- 项目实现的用户查询服务 -->
       <bean id="userDetailsService" class="com.koolyun.security.utils.UserDetailsServiceImpl"/>
       <!--
              重新定义的FilterSecurityInterceptor,使用databaseDefinitionSource提供的url-授权关系定义
       -->
       <bean id="filterSecurityInterceptor" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
              <s:custom-filter before="FILTER_SECURITY_INTERCEPTOR" />
              <property name="accessDecisionManager" ref="accessDecisionManager" />
              <property name="objectDefinitionSource" ref="databaseDefinitionSource" />
       </bean>
       <!-- DefinitionSource工厂,使用resourceDetailsService提供的URL-授权关系. -->
       <bean id="databaseDefinitionSource" class="com.koolyun.security.utils.DefinitionSourceFactoryBean">
              <property name="resourceDetailsService" ref="resourceDetailsService" />
       </bean>
       <!-- 项目实现的URL-授权查询服务 -->
       <bean id="resourceDetailsService" class="com.koolyun.security.service.ResourceDetailsServiceImpl" />
       <!-- 授权判断配置, 将授权名称的默认前缀由ROLE_ -->
       <bean id="accessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
              <property name="decisionVoters">
                     <list>
                           <bean class="org.springframework.security.vote.RoleVoter">
                                  <property name="rolePrefix" value="ROLE_" />
                           </bean>
                           <bean class="org.springframework.security.vote.AuthenticatedVoter" />
                     </list>
              </property>
       </bean>
</beans>

From the configuration, we can see that the bean userDetailsService is a processing class that handles password verification and permission verification.

The following is the implementation code of userDetailsServiceImpl:
public UserDetails loadUserByUsername(String userName)
                     throws UsernameNotFoundException, DataAccessException {
              CsUser user;
              String loginType = userName.split("~~~")[0];
              String username = userName.split("~~~")[1];
              // 查询用户是否存在
                user = securityService.findUserByLoginName(userName);
              if (user == null) {
                     throw new UsernameNotFoundException("用户" + userName + " 不存在");
              }
org.springframework.security.userdetails.User userdetail = new org.springframework.security.userdetails.User(
                           authName, user.getPassword(), enabled, accountNonExpired,
                           credentialsNonExpired, accountNonLocked, grantedAuths);
            return userdetail;
}

The password verification process is not specified here, and here comes the default password verification process of Spring Security.

 
 
The following is the form content of the page:
 
<form action='/j_spring_security_check.do' method="post">   
    <div class="form-group org">
      <label class="control-label visible-ie8 visible-ie9">客户号</label>
      <input class="form-control form-control-solid placeholder-no-fix" type="text" autocomplete="on" placeholder="    客户号" name="orgId" id="orgId" maxlength="15" autofocus="autofocus"/>
    </div>
    <div class="form-group">   
       <label class="control-label visible-ie8 visible-ie9">用户名</label>
       <input class="form-control form-control-solid placeholder-no-fix" type="text" autocomplete="on" placeholder="    用户名" name="j_username_tmp" id="j_username_tmp"/>
    </div>
    <div class="form-group">
       <label class="control-label visible-ie8 visible-ie9">密码</label>
       <input class="form-control form-control-solid placeholder-no-fix" type="password" autocomplete="off" placeholder="   密码"  name="j_password" id="password"/>
    </div>        
    <div class="form-group clearfix">
       <input type="text" id="j_captcha" name="j_captcha" placeholder="验证码" class="form-control form-control-yzm pull-left" size="8" maxlength="4">
       <img src='<c:url value="/commons/jcaptcha.jpg"></c:url>' class="yzm-pic pull-left" id="captchaImg">
</form>

 

The following is the content of chrom DevTools for login and logout. It can be seen that the order here is based on the xml file ( default-target-url is the url that is redirected after successful login by default) and logout-success-url = "/login/index .do" to jump
 

Guess you like

Origin blog.csdn.net/qq_23974323/article/details/104537642