Web开发两大传统艺能,增删改查基础操作已经会写了,还剩下就是用户验证了。Spring Security就是做这个的。主要的功能就是管理用户身份认证(authenticate)和用户权限(authority)。
有两种方式可以为一个项目添加安全管理:声明式和编程式。
Spring Security是通过JSP的Filter技术来实现的,Filter技术本身可以实现对于request和response的预先处理,Spring在这个基础上提供了很多功能。
关于用户认证,Spring Security提供了默认的登录表单页面,也可以自行设计。还支持很多LDAP等第三方认证集成。
老样子,还是通过创建一个项目,来一点一点的看Spring Security的各种功能以及标准的用户身份验证该如何做。这个项目要完成如下内容:
- 创建默认和自定义的登录页面
- 创建用户和角色
- 基于角色保护特定的URL
- 使用JSP标签根据角色显示不同的内容
- 将用户,密码和角色保存在数据库中,先是原始数据,然后是加密保存。
这个项目的创建过程也学一些新东西,采用Maven配置,然后完全采用Java类配置,不采用web.xml。然后也做到像之前一样的尽量将安全代码与业务逻辑代码相分离。
项目初始配置
配置的步骤如下:
- 利用Maven创建项目
- 创建Spring Java配置类
- 通过Spring来初始化前端转发器(而不是web.xml)
- 启动项目,正常运行后准备编写业务代码。
一步一步来,先通过Maven 的 webapp archetype来创建一个新项目securitydemo,然后配置pom.xml,我们的项目需要使用到Spring和JSTL:
<properties>
<springframework.version>5.0.2.RELEASE</springframework.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
这里要查看一下pom.xml中的插件配置是否包含maven-war-plugin 3.2版,使用Intellij选择创建3.0的Maven会自动添加,如果没有,需要手工添加如下:
<pluginManagement>
<plugins>
<plugin>
<!-- Add Maven coordinates (GAV) for: maven-war-plugin -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</pluginManagement>
这里注意,如果创建的Maven Webapp没有src/main/java文件夹,需要自己创建一个,然后在File--Project Structure--左侧Modules--右侧选择src/main/java目录将其标示为Sources。
创建Spring配置类
然后需要创建Spring的配置类,在基础的增删改查项目里,我们通过web.xml启动了Spring的前端转发器,然后通过XML来定义了视图解析器,这里要了解一下如何通过Spring的配置直接来启动前端转发器和配置视图解析器,而不需要web.xml。
在src/main/java/下创建cc.conyli包,之后的代码编写都在这里,然后在包的根目录下创建config/DemoAppConfig.java:
package cc.conyli.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "cc.conyli")
public class DemoAppConfig {
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
@EnableWebMvc
这个注解相当于XML文件里的<mvc:annotation-driven />
,启动了MVC相关的功能,包括转换,格式,验证和@Controller、@RequestMapping等注解。
然后是创建了视图解析器对应的Bean,这个Bean对应XML配置文件里的视图解析器的那一段:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
用心观察的话,可以发现这个Bean对应的类其实是一样的,两种配置其实就是换了个写法。
还有一个重要的内容是配置前端转发器对应的Servlet,在之前是直接用web.xml将全部路径映射到了org.springframework.web.servlet.DispatcherServlet
这个类,为了完成这个工作,需要如下步骤:
- 继承
AbstractAnnotationConfigDispatcherServletInitializer
这个类。
- 重写其中的方法
- 指定servlet mapping 和Spring配置文件的具体位置
我们在和配置文件相同的目录下创建一个继承类MyDispatcherServletInitializer:
package cc.conyli.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class MyDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
//没有使用多配置文件,这里不需要修改
protected Class[] getRootConfigClasses() {
return new Class[0];
}
@Override
//这是获取具体Servlet配置的方法,需要将刚才编写的配置类放进去
protected Class[] getServletConfigClasses() {
return new Class[]{
DemoAppConfig.class
};
}
@Override
//这是上边的servlet的映射,也是一个数组,与上边一对一
protected String[] getServletMappings() {
return new String[]{
"/"
};
}
}
有三个方法需要重写,其中第二个方法会去找Spring的配置文件,然后生成和和第三个方法的路径数组中匹配的前端转发器,合起来就相当于XML配置文件中servlet及对应的servlet-mapping的部分。
到这里实际上web.xml就可以删除了,尝试编译一下报了源文件包javax.servlet.ServletException找不到的错误,是因为缺少一些包,在pom.xml中添加一些依赖:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
上边的那个依赖javax.servlet-api很奇怪,从maven仓库搜到的3.1.0版认不出来,修改成3.0.1版就可以了。
删除web.xml和Maven自动生成的index.jsp,然后运行项目,可以看到日志提示:
org.springframework.web.servlet.DispatcherServlet.noHandlerFound
No mapping found for HTTP request with URI [/] in DispatcherServlet with name 'dispatcher'
可以看到这和XML配置一样,还是去找到了org.springframework.web.servlet.DispatcherServlet
这个前端转发器类,由于没有任何控制器,所以现在匹配不了路径。但是这说明前端转发器已经就绪,不过还不知道视图解析是否正常,编写一个简单的控制器测试一下即可。
简单控制器测试项目工作是否正常
编写一个简单的首页和对应的JSP文件,创建cc.conyli.controller包,编写一个控制器,在WEB-INF/view/里编写一个home.jsp:
package cc.conyli.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HomepageController {
@RequestMapping("/")
public String Homepage() {
return "home";
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Spring Security学习</title>
</head>
<body>
<p>新开始了</p>
</body>
</html>
运行以后成功显示出了自己的jsp,现在就学会了不使用web.xml进行配置Web项目的方法。之后就要进行我们SS级别的学习了。
导入Spring Security
要使用Spring Security,很显然先要引入Spring Security包。
在spring.io/projects里可以看到,Spring Security是独立于Spring Framework的项目。这两个项目的发布周期不同,版本也不同步,因此会有一些兼容性方面的问题。
在我们的项目中,要同时引入Spring Framework和Spring Security,很显然就需要两个项目互相兼容的版本。
Spring Security依赖与spring-security-web和spring-security-config,我们将通过在Maven仓库上寻找包,然后查看其兼容的Spring Framework版本的方式来进行配置。
在https://mvnrepository.com/artifact/org.springframework.security/spring-security-web/5.0.0.RELEASE找到spring-security-web,查看下面的Compile Dependencies部分,可以发现其依赖的框架是Spring Framework 5.0.2.RELEASE版本。
于是我们在pom.xml中配置如下:
<properties>
...
<springsecurity.version>5.0.0.RELEASE</springsecurity.version>
...
</properties>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${springsecurity.version}</version>
</dependency>
同样再去找到spring-security-config,也配置好:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${springsecurity.version}</version>
</dependency>
这里版本号就直接采用和上边一样的版本号。这样就配置好了Spring Security。