Spring Security 系列教程(2)
来源:互联网 发布:农产品网络销售 编辑:程序博客网 时间:2024/05/19 06:14
从本篇开始,将逐步介绍Spring Security的特性。阅读本篇教程之前,需要对 Spring Data JPA有一定了解。
本次教程,我们将实现从数据库读取用户认证以及权限信息
本次教程,将使用到以下的框架(以后的教程,都只会列出新增的框架,之前已经列出的,将不再列出):
- lombok 通过注解方式即可生成Java bean的 getter/setter/builder/constructor 等,具体请参考官网lombok官网
- Spring Data JPA 官方文档
- Swagger 用于生成、描述、调用和可视化 RESTful 风格的API
首先,我们先将本节依赖的环境搭建好。
添加新增的maven依赖
spring data jpa 依赖:
<!--data--><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId></dependency>
lombok 依赖:
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.16</version></dependency>
注:除了添加lombok依赖之外,还需安装IDE插件,如果使用的是idea,直接搜索lombok插件并安装即可
swagger 依赖:
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.7.0</version></dependency><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.7.0</version></dependency>
配置数据源
#禁用http basic认证security.basic.enabled = falsespring.datasource.url=jdbc:mysql://localhost/spring_securityspring.datasource.username=spring.datasource.password=spring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.jpa.hibernate.ddl-auto=updatespring.jpa.properties.hibernate.format_sql=truespring.jpa.open-in-view=truespring.jpa.show-sql=true
在本教程中,将使用MySQL数据库,我们需要手动在MySQL中建立数据库,请按照自己机器的设置配置此处的数据源信息
添加swagger配置类
package me.learningai.config;import io.swagger.annotations.ApiOperation;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.time.LocalDate;/** * @author heyx */@Configuration@EnableSwagger2public class Swagger2Config { private static final String VERSION = "1.0"; @Bean public Docket apiDocket() { return new Docket(DocumentationType.SWAGGER_2) .select() //配置swagger 处理所有添加了 @ApiOperation的方法,用以生成文档 .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) .build() .directModelSubstitute(LocalDate.class, java.sql.Date.class) .directModelSubstitute(LocalDate.class, java.util.Date.class) .apiInfo(apiInfo()); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("Swagger API") .description("base java ee framework") .license("Apache 2.0") .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html") .version(VERSION) .build(); }}
此处仅仅做了最简单的配置,有关swagger其他设置,请参考: 官方文档
最后,我们需要修改 Spring Security设置,允许匿名 Swagger 文档:
WebSecurityConfig.java
@Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() //允许swagger 文档匿名访问 .antMatchers("/swagger*/**","/v2/**", "/webjars/**").permitAll() //设置其他所有请求都需认证 .anyRequest().authenticated() .and() .formLogin().defaultSuccessUrl("/user/me"); }
至此,所需环境以搭建完毕,运行程序并访问 http://localhost:8080/swagger-ui.html ,我们将看到以下的界面:
现在,我们将正式开始实现从数据库读取用户认证信息。
第一步,我们先来看一下数据库定义:
表结构非常简单,一张用户表,一张权限表以及它们之间的关联表。
关于表的entity/repository/service就不贴出来了,具体实现,请查看源码。
下面,我们需要自定义class 并实现 UserDetailsService 接口,UserDetailsService是Spring security加载用户信息的入口,里面只有一个方法:
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
这个方法返回了 UserDetails 用于提供给Spring security 进行用户权限的判断。
SpringDataUserDetailsService:
package me.learningai.security.core;import me.learningai.security.entity.User;import me.learningai.security.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.core.userdetails.UsernameNotFoundException;/** * @author heyx */public class SpringDataUserDetailsService implements UserDetailsService { private UserService userService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userService.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("username:" + username + " not found"); } return new AuthorityUser(user); } @Autowired public void setUserService(UserService userService) { this.userService = userService; }}
这里只是对UserDetailsService做了很简单的实现,通过用户名从 UserService 加载了用户信息,并转换成了 AuthorityUser了,AuthorityUser 实现了 UserDetails 接口。
最后,我们还需修改一下Spring security的配置,让它能从我们自定义的 UserDetailsService 中加载用户信息。
package me.learningai.config;import me.learningai.security.core.SpringDataUserDetailsService;import org.springframework.context.annotation.Bean;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;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.WebSecurityConfigurerAdapter;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;/** * spring security 配置. * @author heyx */@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //设置自定义UserDetailService,用以从数据库加载用户信息 auth.userDetailsService(springDataUserDetailsService()) //设置密码加密 .passwordEncoder(passwordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() //允许swagger 文档匿名访问 .antMatchers("/swagger*/**","/v2/**", "/webjars/**").permitAll() //设置其他所有请求都需认证 .anyRequest().authenticated() .and() .formLogin().defaultSuccessUrl("/user/me"); } @Bean public SpringDataUserDetailsService springDataUserDetailsService() { return new SpringDataUserDetailsService(); } @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(8); }}
此处定义了用户密码加密策略,有需要可自行实现 PasswordEncoder 接口并修改配置。
其他接口:
具体参数,可参考 swagger 文档,http://localhost:8080/swagger-ui.html
现在,让我们启动应用,并访问 http://localhost:8080/user/me,因为没有认证,所以会跳转到登陆页面去,在登陆页面输入用户名密码(预置数据,用户名:user,密码:123456),点击登陆后,我们就会跳转到 http://localhost:8080/v1/user/me页面获取当前登录用户的信息了:
注:本教程提供的都是 rest 接口,为了简便起见,还是使用了Spring security 的formlogin 方式进行登陆,关于这个问题,后面会专门写一篇博客介绍编写无状态的 rest接口,在那里,会提供这个问题的解决办法。
好了,本次教程也到此结束了,因为版面的原因,controller/service/repository都没有直接贴代码,有需要的可直接获取:源码
下一篇教程,会介绍Spring security 如何结合Spring session。
- Spring Security 系列教程(2)
- 《Spring Security教程系列》一.Spring Security简介
- Spring Security 系列教程-Hello World
- Spring Cloud Security系列教程一:入门
- Spring Security 系列教程-Hello World
- 《Spring Security教程系列》二.初识Java 配置
- 《Spring Security教程系列》三.HttpSecurity的使用
- spring security详解教程
- spring security 教程入门
- spring security教程
- Spring Security教程
- Spring Security教程目录
- Spring Security教程(一)
- Spring Security教程(二)
- Spring Security教程(三)
- Spring Security教程(四)
- Spring Security教程(五)
- Spring Security教程(六)
- 基于docker的caffe环境搭建与使用示例
- Ref 与 Out 的区别
- 11-S3C2440驱动学习(七)嵌入式linux-字符设备的另一种写法及RTC驱动程序分析和字符设备驱动框架总结
- 非平稳时间序列季节效应分析
- 定义自己异常
- Spring Security 系列教程(2)
- SEO之HTML优化:让你的网站HTML代码更符合SEO规范
- 数据挖掘领域十大经典算法
- Binder机制开启篇
- CSS之Responsive网页设计的三个特性
- 图像处理中的线性和非线性滤波器(上)
- 百度文库上传的文档嵌入链接的小技巧
- 一起学JAVA之《spring boot》02-开发您的第一个Spring Boot应用程序
- 【JZOJ5165】小W的动漫