前面我们用了简单的三步就完成了一个Spring- Secutiry的搭建,主要是通过添加auto-config属性和http元素实现的,但是在实际工作中要比这个复杂的太多,现在我们按部就班的来完善我们的权限管理,遇到理论问题,可以去查看专家博客:http://lengyun3566.iteye.com/blog关于Spring Secutiry3翻译。

       现在我们为我们JBCP Pets在线商店完善一下,我们先配置自己默认的登录界面,有兴趣的可以从网上找一个,这里我不用书上的登录界面,我从网上找的模板。

  在WebContent下创建views文件夹,下面创建 login.jsp(样式见附件),关于登录页注意一下两点:

  • Form action必须与UsernamePasswordAuthenticationFilter过滤器的action的配置相一致。默认的form action是j_spring_security_check;

  • 用户名和密码的表单域要与servlet的标准相一致。默认j_usernamej_password是文本域的名字。

 需要注意的是,必须使用post方式的form提交,否则UsernamePasswordAuthenticationFilter会拒绝登录请求。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@include file="/base/taglibs.jsp"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>Login Form</title>
  <link rel="stylesheet" href="${cms}/css/style.css">
</head>
<body>
  <section class="container">
    <div class="login">
      <h1>Login to Web App</h1>
      <form method="post" action="/j_spring_security_check">
        <p><input type="text" name="j_username" value="" placeholder="用户名"></p>
        <p><input type="password" name="j_password" value="" placeholder="密码"></p>
        <p class="remember_me">
          <label>
            <input type="checkbox" name="remember_me" id="remember_me">
            Remember me on this computer
          </label>
        </p>
        <p class="submit"><input type="submit" name="commit" value="Login"></p>
      </form>
    </div>

    <div class="login-help">
      <p>Forgot your password? <a href="index.html">Click here to reset it</a>.</p>
    </div>
  </section>
</body>
</html>

创建SpringMVC的控制器类BaseController和LoginController

package com.pet.Controller;

import org.springframework.stereotype.Controller;

/**
 * 
  * @author zangyn
  * @date 2016-11-22 下午2:34:28
  * @Description: 用来提供公共功能
  * @throws
 */
@Controller
public class BaseController {

}
package com.pet.Controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * 
  * @author zangyn
  * @date 2016-11-22 下午2:34:48
  * @Description: 登录功能控制器
  * @throws
 */
@Controller
public class LoginController extends BaseController{
	
	 @RequestMapping(method=RequestMethod.GET,value="/login.do")
	  public void home() {
	  }
}

这里我们写代码要考虑到控制器类可能存在需要公用的功能,所以构造BaseController这个类来放置重复使用的方法。现在就要将控制器加入SpringMVC容器中,所以需要修改SpringMVC的配置文件,通过扫描加入注解后的类和方法。

<?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:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/jdbc  http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
	">	
	<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
	    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
	   <property name="prefix" value="/views/"/>
	   <property name="suffix" value=".jsp"/>
	</bean>
	 <!-- 自动扫描注解标注的类或方法 -->
	<context:component-scan base-package="com.pet"/>
</beans>

@RequestMapping标注的方法如果返回空值,则返回的逻辑视图名为value的值,因此上面

 @RequestMapping(method=RequestMethod.GET,value="/login.do")
	  public void home() {
	  }

实际返回的是URL= prefix前缀+视图名称 +suffix后缀组成,这样就会返回我们在views下的login.jsp.

现在我们配置web.xml下的<welcome-file-list>值为login.do,这样就能调用SpringMVC

<?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" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="DogStoreApp" version="2.5">
  <display-name>Dog Store</display-name>
   <!-- 集成spring的通用配置 -->
   <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
     /WEB-INF/dogstore-security.xml  
    /WEB-INF/dogstore-base.xml 
	</param-value>
   </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!-- SpringMVC前端控制器 -->
 <servlet>
 <servlet-name>dogstore</servlet-name>
 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>  
 </servlet>
 <servlet-mapping>
    <servlet-name>dogstore</servlet-name>
    <url-pattern>*.do</url-pattern>
    <url-pattern>/login.do</url-pattern>
  </servlet-mapping>
  <!-- springSecurity核心过滤器配置 -->
  <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>
  
  <welcome-file-list>
  <welcome-file>login.do</welcome-file>
  </welcome-file-list>
</web-app>

最后,我们还需要Spring Security的自动配置来引用我们新的登录页面。如果你在此时迫不及待想看一下效果的话,我们实际上只是为应用增加了一个新的工作页面。按照上面的流程并输入以下的地址http://localhost:8080/pet/login.do,看看发生了什么。

什么?你是否发现你的请求首先被Spring Security拦截了(被重定向到spring_security_login)并且能够看见那个登录的form?这是因为Spring Security依旧指向了DefaultLoginPageGeneratingFilter生成的默认登录页。一旦你通过了这个过滤器生成的默认登录页,你才能够看到新的自定义登录页。最后一步就是要移除默认页并使用我们的登录form作为登录页。

因此我们要修改dogstore-security.xml文件让login.do能被任何人访问

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/security 
		http://www.springframework.org/schema/security/spring-security-3.1.xsd">
	<http auto-config="true" use-expressions="true">
         <intercept-url pattern="/login.do" access="permitAll"/>
		<intercept-url pattern="/*" access="hasRole('ROLE_USER')"/>
	</http>
	<authentication-manager alias="authenticationManager">
		<authentication-provider>
			<user-service>
				<user authorities="ROLE_USER" name="guest" password="guest"/>
			</user-service>
		</authentication-provider>
	</authentication-manager>	
</beans:beans>

注意这个use-expressions="true"这个用法,SpEL使用Spring 表达式语言,可用来定义语法复杂的投票规则

现在我们来登录http://localhost:8080/pet/,返回首页登录界面:

wKiom1g0BOGDwMoBAAEu5cuGD4Q505.png