Spring Security 系列教程(2) - JDBC Authentication
2017-06-25 19:49
148 查看
从本篇开始,将逐步介绍Spring Security的特性。阅读本篇教程之前,需要对 Spring Data JPA有一定了解。
本次教程,我们将实现从数据库读取用户认证以及权限信息
本次教程,将使用到以下的框架(以后的教程,都只会列出新增的框架,之前已经列出的,将不再列出):
lombok 通过注解方式即可生成Java bean的 getter/setter/builder/constructor 等,具体请参考官网lombok官网
Spring Data JPA 官方文档
Swagger 用于生成、描述、调用和可视化 RESTful 风格的API
首先,我们先将本节依赖的环境搭建好。
添加新增的maven依赖
spring data jpa 依赖:
lombok 依赖:
注:除了添加lombok依赖之外,还需安装IDE插件,如果使用的是idea,直接搜索lombok插件并安装即可
swagger 依赖:
配置数据源
在本教程中,将使用MySQL数据库,我们需要手动在MySQL中建立数据库,请按照自己机器的设置配置此处的数据源信息
添加swagger配置类
此处仅仅做了最简单的配置,有关swagger其他设置,请参考: 官方文档
最后,我们需要修改 Spring Security设置,允许匿名 Swagger 文档:
WebSecurityConfig.java
至此,所需环境以搭建完毕,运行程序并访问 http://localhost:8080/swagger-ui.html ,我们将看到以下的界面:
现在,我们将正式开始实现从数据库读取用户认证信息。
第一步,我们先来看一下数据库定义:
表结构非常简单,一张用户表,一张权限表以及它们之间的关联表。
关于表的entity/repository/service就不贴出来了,具体实现,请查看源码。
下面,我们需要自定义class 并实现 UserDetailsService 接口,UserDetailsService是Spring security加载用户信息的入口,里面只有一个方法:
这个方法返回了 UserDetails 用于提供给Spring security 进行用户权限的判断。
SpringDataUserDetailsService:
这里只是对UserDetailsService做了很简单的实现,通过用户名从 UserService 加载了用户信息,并转换成了 AuthorityUser了,AuthorityUser 实现了 UserDetails 接口。
最后,我们还需修改一下Spring security的配置,让它能从我们自定义的 UserDetailsService 中加载用户信息。
此处定义了用户密码加密策略,有需要可自行实现 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。
本次教程,我们将实现从数据库读取用户认证以及权限信息
本次教程,将使用到以下的框架(以后的教程,都只会列出新增的框架,之前已经列出的,将不再列出):
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 = false spring.datasource.url=jdbc:mysql://localhost/spring_security spring.datasource.username= spring.datasource.password= spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.format_sql=true spring.jpa.open-in-view=true spring.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 @EnableSwagger2 public 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 */ @EnableWebSecurity public 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 接口并修改配置。
其他接口:
API | Method | 描述 |
---|---|---|
/v1/user | POST | 创建用户 |
/v1/user/me | GET | 获取当前登录用户 |
/v1/authority | POST | 创建Authority |
现在,让我们启动应用,并访问 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 从入门到进阶系列教程
- Spring Security 系列教程-Hello World
- Spring Security 系列教程-Hello World
- Csharp+Asp.net系列教程(二)
- Csharp+Asp.net系列教程(六)
- Microsoft .Net Remoting系列教程之三:Remoting事件处理全接触
- JDBC系列教程(三)---语句
- Csharp+Asp.net系列教程(五)
- 80x86保护模式系列教程(2)分段管理机制
- [软件架构师系列教程-1]白话软件架构与架构师
- Csharp+Asp.net系列教程(六)
- 80x86保护模式系列教程(1)保护方式简介
- [软件架构师系列教程-3]DotNET架构的核心开发技术
- 蛙蛙推荐:微软网络讲座系列教程视频下载(2004年1月到2005年4越)
- [软件架构师系列教程-2]怎样成为优秀的软件模型设计者?
- Csharp+Asp.net系列教程(一)
- 80x86保护模式系列教程(5)任务状态段和控制门
- Csharp+Asp.net系列教程(四)
- Csharp+Asp.net系列教程(三)
- 教程系列之配置Oracle调试环境