实战Spring Security技术栈开发企业级认证与授权

系统架构

在这里插入图片描述

什么是Spring IO Platform

Spring IO Platform,简单的可以认为是一个依赖维护平台,该平台将相关依赖汇聚到一起,针对每个依赖,都提供了一个版本号;

这些版本对应的依赖都是经过测试的,可以保证一起正常使用。

为什么要使用Spring IO Platform

主要是解决依赖版本冲突问题,例如在使用Spring的时候,经常会使用到第三方库,一般大家都是根据经验挑选一个版本号或挑选最新的,随意性较大,其实这是有问题的,除非做过完整的测试,保证集成该版本的依赖不会出现问题,且后续集成其它第三方库的时候也不会出现问题,否则风险较大,且后续扩展会越来越困难,因为随着业务复杂度的增加,集成的第三方组件会越来会多,依赖之间的关联也会也来越复杂。

好消息是,Spring IO Platform能很好地解决这些问题,我们在添加第三方依赖的时候,不需要写版本号,它能够自动帮我们挑选一个最优的版本,保证最大限度的扩展,而且该版本的依赖是经过测试的,可以完美的与其它组件结合使用。

Spring IO Platform pom

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.imooc.security</groupId>
	<artifactId>imooc-security</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<packaging>pom</packaging>

	<properties>
		<imooc.security.version>1.0.0-SNAPSHOT</imooc.security.version>
	</properties>
#有这两个依赖就可以将项目的依赖管理起来了start
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>io.spring.platform</groupId>
				<artifactId>platform-bom</artifactId>
				<version>Brussels-SR4</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.SR2</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
#有这两个依赖就可以将项目的依赖管理起来了end
#配置maven的编译信息start
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</build>
	#配置maven的编译信息end
	<modules>
		<module>../imooc-security-app</module>
		<module>../imooc-security-browser</module>
		<module>../imooc-security-core</module>
		<module>../imooc-security-demo</module>
		<module>../imooc-security-authorize</module>
	</modules>
</project>

一个模块引入另外一个模块的依赖

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<artifactId>imooc-security-app</artifactId>
	<parent>
		<groupId>com.imooc.security</groupId>
		<artifactId>imooc-security</artifactId>
		<version>1.0.0-SNAPSHOT</version>
		<relativePath>../imooc-security</relativePath>
	</parent>
	#这边引入了com.imooc.security模块的全部依赖,需在父类中加入版本说明
	<dependencies>
		<dependency>
			<groupId>com.imooc.security</groupId>
			<artifactId>imooc-security-core</artifactId>
			<version>${imooc.security.version}</version>
		</dependency>
	</dependencies>
</project>

打包一个可执行web服务的jar包?加一个编译插件

在打包成web服务模块的.pom文件中加入插件

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<version>1.5.6.RELEASE</version>
			<executions>
				<execution>
					<goals>
						<goal>repackage</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
	<finalName>demo</finalName>
</build>

restful Api与常规的Api的区别

1.常规的使用json来定义请求的成功或者失败
2.restful Api使用http的状态码来确定请求的成功或者失败

restful Api的描述

在这里插入图片描述

Spring的测试框架、测试用例的使用

1.模块中加入pom依赖

      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <version>1.5.6.RELEASE</version>
      </dependency>

2.在模块中添加测试用例

package com.imooc.web.controller;

import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

@RunWith(SpringRunner.class) //表示如何来运行这个测试用例,我们用SpringRunner来运行
@SpringBootTest //表示这个类是一个springBoot的测试用例
public class UserControllerTest {

	//因为我们要测的是一个web程序,所以我们要伪造一个Mvc的环境,伪造的
	// 环境不会真正的启动我们的tomcat,所以测试用例执行的时候会很快
	@Autowired
	private WebApplicationContext wac;
	
	private MockMvc mockMvc;//伪造mvc的环境
	
	@Before //会在测试用例执行之前执行
	public void setup(){
		mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();//伪造一个mvc环境
	}
	
	//开始写一个测试用例
	@Test
	public void whenQuerySuccess() throws Exception {
		String result = mockMvc.perform(get("/user").param("username", "jojo").param("age", "18").param("ageTo", "60").param("xxx", "yyy")
						// .param("size", "15")
						// .param("page", "3")
						// .param("sort", "age,desc")
						.contentType(MediaType.APPLICATION_JSON_UTF8))
				.andExpect(status().isOk()).andExpect(jsonPath("$.length()").value(3))
				.andReturn().getResponse().getContentAsString();
		
		System.out.println(result);
	}
	
}

idea导入eclipse的maven项目

在这里插入图片描述

idea运行单个测试用例及运行所有测试用例的方法

1.双击单个方法,run as
2.在文件上 run as

Spring的一些用法

1.@PathVariable将路径上的参数作为方法参数导入
2.@GetMapping("/{id:\d+}") ///使用正则表达式表示接受数字类型的参数

@JsonView的使用

在这里插入图片描述
1-2
在这里插入图片描述
3.在controller中指定视图
在这里插入图片描述

********************** 1.RESTful Api *****************************

在这里插入图片描述
1.RequestBody映射请求体到javaj方法的参数///
2.日期类型参数的处理
///通过传递时间戳到前端,让前台来决定展示格式
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3.valid注解和BindingResult验证请求参数的合法性并处理验证结果
1)添加@valid的
在这里插入图片描述
2)添加需要验证的字段
在这里插入图片描述
3)BindingResult让验证可以进入函数体
///比如在校验参数没过时,需要记录日志
在这里插入图片描述

************************************************************

在这里插入图片描述
4)常用的验证注解
在这里插入图片描述
在这里插入图片描述

获取错误的字段和信息

在这里插入图片描述
5)自定义验证消息
在这里插入图片描述
6)自定义验证注解
1.自定义验证注解
在这里插入图片描述

2.验证逻辑
在这里插入图片描述
3.调用验证器
在这里插入图片描述

RESTful Api错误处理机制

在这里插入图片描述
1)Spring Boot 中默认的错误处理机制

2)如何自定义异常处理
定义浏览器的错误请求页面
在这里插入图片描述
自定义运行时异常
1)异常类处理

package com.imooc.exception;

public class UserNotExistException extends RuntimeException {
    private static final long serialVersionUID = -6112780192479692859L;

    private String id;

    public UserNotExistException(String id) {
        super("user not exist");
        this.id = id;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

2)调用抛出异常

throw new UserNotExistException (String id);

3)添加自己的异常信息(将id信息返回到异常信息)

package com.imooc.web.controller;


import com.imooc.exception.UserNotExistException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice //代表这个类的方法都是处理其他Controller控制器所抛出的异常的 =>不处理请求,值处理controller请求
public class ControllerExceptionHandler {
    @ExceptionHandler(UserNotExistException.class) //任何一个方法抛出一个UserNotExistException异常是,都会执行下面的方法
    @ResponseBody //返回json
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Map<String, Object> handleUserNotExistException(UserNotExistException ex) { //拿到抛出的异常
        Map<String, Object> result = new HashMap<>();
        result.put("id", ex.getId());
        result.put("message", ex.getMessage());
        return result;
    }
}

RESTful Api拦截器

在这里插入图片描述
1)过滤器

/**
 * 
 */
package com.imooc.web.filter;

import java.io.IOException;
import java.util.Date;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * @author zhailiang
 *
 */
//@Component  //要让过滤器起作用,申明成一个spring的Component,所有的流程都会经过这个过滤器
public class TimeFilter implements Filter {

	/* (non-Javadoc)
	 * @see javax.servlet.Filter#destroy()
	 */
	@Override
	public void destroy() {
		//销毁
		System.out.println("time filter destroy");
	}

	/* (non-Javadoc)
	 * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
	 */
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		//执行
		System.out.println("time filter start");
		long start = new Date().getTime();
		chain.doFilter(request, response);
		System.out.println("time filter 耗时:"+ (new Date().getTime() - start));
		System.out.println("time filter finish");
	}

	/* (non-Javadoc)
	 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
	 */
	@Override
	public void init(FilterConfig arg0) throws ServletException {
		//初始化
		System.out.println("time filter init");
	}

}

如何把一个普通(第三方的过滤器)类加到项目过滤器链中
/**
 * 
 */
package com.imooc.web.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.imooc.web.filter.TimeFilter;
import com.imooc.web.interceptor.TimeInterceptor;

/**
 * @author zhailiang
 *
 */
@Configuration  //**告诉spring这个类是一个配置类
public class WebConfig extends WebMvcConfigurerAdapter {
	
	@SuppressWarnings("unused")
	@Autowired
	private TimeInterceptor timeInterceptor;
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
//		registry.addInterceptor(timeInterceptor);
	}
	
//	@Bean //**注册一个FilterRegistrationBean的bean
	public FilterRegistrationBean timeFilter() {
		
		FilterRegistrationBean registrationBean = new FilterRegistrationBean();
		
		TimeFilter timeFilter = new TimeFilter();
		registrationBean.setFilter(timeFilter);//**设置过滤器
		
		List<String> urls = new ArrayList<>();
		urls.add("/*");//**配置过滤器的URL
		registrationBean.setUrlPatterns(urls);
		
		return registrationBean;
		
	}

}

2)拦截器
//过滤器不知道请求的处理函数?
1.申明拦截器

/**
 * 
 */
package com.imooc.web.interceptor;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author zhailiang
 *
 */
@Component
public class TimeInterceptor implements HandlerInterceptor {

	/* (non-Javadoc)
	 * @see org.springframework.web.servlet.HandlerInterceptor#preHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("preHandle");
		
		System.out.println(((HandlerMethod)handler).getBean().getClass().getName());
		System.out.println(((HandlerMethod)handler).getMethod().getName());
		
		request.setAttribute("startTime", new Date().getTime());
		return true;
	}

	/* (non-Javadoc)
	 * @see org.springframework.web.servlet.HandlerInterceptor#postHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, org.springframework.web.servlet.ModelAndView)
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("postHandle");
		Long start = (Long) request.getAttribute("startTime");
		System.out.println("time interceptor 耗时:"+ (new Date().getTime() - start));

	}

	/* (non-Javadoc)
	 * @see org.springframework.web.servlet.HandlerInterceptor#afterCompletion(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("afterCompletion");
		Long start = (Long) request.getAttribute("startTime");
		System.out.println("time interceptor 耗时:"+ (new Date().getTime() - start));
		System.out.println("ex is "+ex);

	}

}

2.注册拦截器
在这里插入图片描述
3)切片

_Kc
发布了69 篇原创文章 · 获赞 9 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_26775359/article/details/103931122