在本节,将演示基于Spring Security安全认证功能。该应用代码可以在security basic目录下找到。
19.5.1 添加依赖
添加Spring Security的依赖时,由于是使用的snapshot版本,所以,要配置Spring Snapshots仓库。配置如下。
<!-- Spring Snapshots仓库 --> <repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> </repository> </repositories> <properties> <spring.version>5.1.5.RELEASE</spring.version> <jetty.version>9.4.14.v20181114</jetty.version> <jackson.version>2.9.7</jackson.version> <spring-security.version>5.2.0.BUILD-SNAPSHOT</spring-security.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-servlet</artifactId> <version>${jetty.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency><!-- 安全相关的依赖 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring-security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring-security.version}</version> </dependency> </dependencies>
19.5.2 添加业务代码
业务代码里面包含了模型和控制器。
1.User模型
User类代码如下。
package com.waylau.spring.mvc.vo; public class User { private String username; private Integer age; public User(String username, Integer age) { this.username = username; this.age = age; } //省略getter/setter方法 }
2.控制器
控制器HelloController代码如下。
package com.waylau.spring.mvc.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.waylau.spring.mvc.vo.User; @RestController public class HelloController { @RequestMapping("/hello") public String hello() { return "Hello World! Welcome to visit waylau.com!";} @RequestMapping("/hello/way") public User helloWay() { return new User("Way Lau", 30); } }
上述控制器的逻辑非常简单,当访问“/hello”时,会响应一段文本;当访问“/hello/way”会返回一个POJO对象。
该POJO对象,可以根据消息转换器的设置,来生成不同格式的消息。
19.5.3 配置消息转换器
添加Spring Web MVC的配置类MvcConfiguration,并在该配置中启用消息转换器。
package com.waylau.spring.mvc.configuration; import java.util.List; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @EnableWebMvc // 启用MVC @Configuration public class MvcConfiguration implements WebMvcConfigurer { public void extendMessageConverters(List<HttpMessageConverter<?>> cs) { // 使用Jackson JSON来进行消息转换 cs.add(new MappingJackson2HttpMessageConverter()); } }
由于预先在pom.xml中添加了Jackson JSON的依赖,因此可以使用
Jackson JSON来进行消息转换,将响应消息体转为JSON格式。
19.5.4 配置Spring Security
以下是针对Spring Security的配置。
package com.waylau.spring.mvc.configuration; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAd apter; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.provisioning.InMemoryUserDetailsManager; @EnableWebSecurity // 启用Spring Security功能 public class WebSecurityConfig extends WebSecurityConfigurerAdapter { /** * 自定义配置 */ @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated()//所有请求都需认证 .and() .formLogin() // 使用form表单登录 .and() .httpBasic(); // HTTP基本认证 } @SuppressWarnings("deprecation") @Bean public UserDetailsService userDetailsService() { InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.createUser( User.withDefaultPasswordEncoder() // 密码编码器 .username("waylau") // 用户名 .password("123") // 密码 .roles("USER") // 角色 .build() ); return manager; } }
在上述配置中,要启动Spring Security功能,需要在配置类上添加@EnableWebSecurity注解。
安全配置类WebSecurityConfig继承自
WebSecurityConfigurerAdapter。WebSecurity Configurer Adapter提供用于创建一个Websecurityconfigurer实例方便的基类,允许自定义重写其方法。这里,我们重写了configure方法:authorizeRequests().anyRequest().authenticated()方法意味着所有请求都需认证;formLogin()方法表明这是基于表单的身份验证;httpBasic()方法表明该认证是一个HTTP基本认证。
UserDetailsService用于提供身份认证信息。本例使用了基于内存的信息管理器InMemory UserDetailsManager,同时初始化了一个用户名为“waylau”、密码为“123”、角色为“USER”的身份信息。
withDefaultPasswordEncoder()方法指定了该用户身份信息使用默认的密码编码器。
19.5.5 创建应用配置类
AppConfiguration是整个应用的配置类,用于导入Spring Web MVC及Spring Security的配置信息。代码如下。
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @ComponentScan(basePackages = { "com.waylau.spring" }) @Import({ WebSecurityConfig.class, MvcConfiguration.class}) public class AppConfiguration { }
19.5.6 创建内嵌Jetty的服务器
创建内嵌了Jetty的服务器,代码如下。
package com.waylau.spring.mvc; import java.util.EnumSet; import javax.servlet.DispatcherType; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;import org.springframework.web.filter.DelegatingFilterProxy; import org.springframework.web.servlet.DispatcherServlet; import com.waylau.spring.mvc.configuration.AppConfiguration; public class JettyServer { private static final int DEFAULT_PORT = 8080; private static final String CONTEXT_PATH = "/"; private static final String MAPPING_URL = "/*"; public void run() throws Exception { Server server = new Server(DEFAULT_PORT); server.setHandler(servletContextHandler(webApplicationContext())); server.start(); server.join(); } private ServletContextHandler servletContextHandler(WebApplicationContext ct) { // 启用Session管理器 ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.SESSIONS); handler.setContextPath(CONTEXT_PATH); handler.addServlet(new ServletHolder(new DispatcherServlet(ct)), MAPPING_URL); handler.addEventListener(new ContextLoaderListener(ct)); // 添加Spring Security过滤器 FilterHolder filterHolder=new FilterHolder(DelegatingFilterProxy.class); filterHolder.setName("springSecurityFilterChain"); handler.addFilter(filterHolder, MAPPING_URL, EnumSet.of(DispatcherType.REQUEST)); return handler; } private WebApplicationContext webApplicationContext() { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(AppConfiguration.class); return context; } }
JettyServer将Spring的上下文Servlet、监听器、过滤器等信息都传给了Jetty服务。
19.5.7 应用启动器
创建应用启动类Application,代码如下。
package com.waylau.spring.mvc; public class Application { public static void main(String[] args) throws Exception { new JettyServer().run(); } }
19.5.8 运行应用
右键运行Application类即可启动应用。
访问
http://localhost:8080/hello/way,会跳转到登录界面,意味着被安全认证拦截了。正如WebSecurityConfig所配置的那样,登录界面是一个form表单,
尝试输入一个错误的用户名和密码,可以看到所示的错误提示信息。
用初始化好的用户名和密码进行成功登录,可以看到能够正常访问应用的API
19.6 本章小结
本章介绍了分布式系统安全性的基本概念、加密算法,同时也介绍了安全通道及访问控制。本章也演示了如何基于Spring Security框架来实现安全认证。
本文就是愿天堂没有BUG给大家分享的内容,大家有收获的话可以分享下,想学习更多的话可以到微信公众号里找我,我等你哦。