上一篇(在项目里面引入spring-security会发生什么)咱们将 Spring-seccurity 引入到了咱们的spring-boot工程中,没有作多余的配置,spring-security 就已经默认帮咱们配置了一个拦截器,应用启动后,当咱们访问应用提供的资源时,都会跳转到 security 为咱们提供的一个默认登录页,当咱们输入security为咱们提供的用户名和密码,登录成功后,就能够获取咱们须要的资源。那么问题来了!咱们如何自定义本身的登陆页面,以及使用咱们本身的用户信息去登陆呢?html
为了避免影响以前的版本,咱们这里新建一个模块 spring-security-02,以前的版本是spring-security-01. https://github.com/nimo10050/spring-security-sample/tree/master/spring-security-02git
依赖跟上个版本同样,以下:github
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
既然咱们须要自定义一些东西,只能经过额外配置的方式来实现。因此这里引入了spring-security的配置类web
添加 @Component注解spring
添加 Spring-security 的注解 EnableWebSecurity 标记这是 security的 配置类数据库
继承 WebSecurityConfigurerAdapter 重写它的配置方法api
重写 configure(HttpSecurity http) 方法是为了定义登录页ide
重写 configure(AuthenticationManagerBuilder auth) 是为了定义登陆逻辑spring-boot
package com.example.demo.config; import com.example.demo.config.service.UserDetailServiceImpl; 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.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; [@Component](https://my.oschina.net/u/3907912) @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { [@Override](https://my.oschina.net/u/1162528) protected void configure(HttpSecurity http) throws Exception { http.csrf().disable();// 必须有, 否则会 403 forbidden http.formLogin() .loginPage("/loginPage.html")// 自定义登陆页 .loginProcessingUrl("/form/login");// 自定义登陆 action, 名字随便起 // passwordParameter("password") 配置 form 表单 密码的 name 属性值 // usernameParameter("username") 配置 form 表单 用户名的 name 属性值 // 访问 "/form/login", "/loginPage.html" 放行 http.authorizeRequests().antMatchers("/form/login", "/loginPage.html").permitAll() .anyRequest().authenticated(); } /** * 配置 用户登陆处理类 * * [@param](https://my.oschina.net/u/2303379) auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { /* 将用户信息存储到内存中 实际上不会这样作,了解下便可 auth.inMemoryAuthentication() .withUser("zhangsan") .password(passwordEncoder().encode("123456")) .authorities("admin");*/ auth.userDetailsService(userDetailsService()); } /** * 自定义登陆处理 * * @return */ @Bean public UserDetailsService userDetailsService() { return new UserDetailServiceImpl(); } /** * 加密工具 * 2.x 版本的 spring-security-starter 必须加上 * * @return */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
经过重写 UserDetailService 接口的 loadUserByUsername方法来实现登陆逻辑,在loadUserByUsername 方法里咱们能够读取数据库或者其余存储介质,来校验咱们的用户是否存在。最后将咱们实现的类配置到config方法中。工具
/** * 自定义登陆处理逻辑 */ public class UserDetailServiceImpl implements UserDetailsService { /* @Autowired private PasswordEncoder passwordEncoder;*/ /** * @param username 登陆页面输入的用户名 * @return * @throws UsernameNotFoundException */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // TODO 根据 username 去用户表查询出来用户的信息,而后进行验证 // 验证成功后,返回Spring-Security 提供的 User 对象 // 对应三个构造参数依次是: 1.用户名 2.密码(通过 passwordEncoder 加密后的密码) 3.权限列表 return new User(username, "$2a$10$g1gzj4KvMNY1kMZT1xDx9ufLuaDvCFDpX.PdETx85zQwXI/Mn4ttC", AuthorityUtils.createAuthorityList("admin")); } public static void main(String[] args) { System.out.println(new BCryptPasswordEncoder().encode("123456"));// $2a$10$g1gzj4KvMNY1kMZT1xDx9ufLuaDvCFDpX.PdETx85zQwXI/Mn4ttC } }
http.authorizeRequests().antMatchers("/form/login","/loginPage.html").permitAll().anyRequest().authenticated();
当咱们定义了UserDetailService,应用启动时控制台就不会打印默认密码了。
高版本的 security 必需要配置密码加密工具类。否则会报错
passwordEncoder is null
spring-security 提供的功能特别多,咱们须要选择性地去使用 security 提供的 api,而后去定制咱们的需求。一步一步来,不要盲目地把别人写好的案例拷贝到本身的项目中,一个成型的案例,里面的配置每每都是一大堆,根本无从看起(我刚开始就是这样,把别人的security案例中的每一个方法,每一个api都扣一遍,很费时间),英文官方文档能看个大概(要怪本身阅读文档能力不够),看了无数的相关博客,每一篇博客大概只有十分之一是我想要的。最后把这些知识碎片组合在一块儿,通过本身编码实现,才有这一系列入门踩坑博客。但愿能帮助有须要的人。