SpringBoot应用篇(二):SpringSecurity实现带验证码的登录认证 附代码

一、文章简介

本文简要介绍了spring security的基本原理和实现,并基于springboot整合了spring security实现了基于数据库管理的用户的登录和登出,登录过程实现了验证码的校验功能。

完整代码地址:https://github.com/hello-shf/spring-security.git

二、spring security框架简介

  Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。主要包括:用户认证(Authentication)和用户授权(Authorization)两个部分。用户认证指的是验证某个用户能否访问该系统。用户认证过程一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。用户授权指的是验证某个用户是否有权限执行某个操作或访问某个页面。通常在一个企业级的系统中不同的用户所具有的权限也是不同的,简单的来说比如普通用户和管理员的区别,管理员显然具有更高的权限。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。spring security的主要核心功能为认证和授权,所有的架构也是基于这两个核心功能去实现的。

三、spring security原理

  Spring security提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI,和AOP功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。Spring Security对Web安全性的支持大量地依赖于Servlet过滤器。这些过滤器拦截进入请求,并且在应用程序处理该请求之前进行某些安全处理。 Spring Security提供有若干个过滤器,它们能够拦截Servlet请求,并将这些请求转给认证和访问决策管理器处理,从而增强安全性。

 四、spring boot整合spring security

4.1 准备工作

4.1.1数据库

 View Code

 

4.1.2 pom.xml依赖

 View Code

4.1.3  application.properties

1 spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=GMT
2 spring.datasource.driver-class-name=com.mysql.jdbc.Driver
3 spring.datasource.username=root
4 spring.datasource.password=

 

4.2 代码实现

4.2.1 t_user表的实体类TUser的基本操作

实体类的基本增删改查可依据项目需要自行选择合适的ORM框架,此处我采用的是jpa实现的基本用户查询操作。此模块不在过多赘述,直接上代码

TUser.java实体类

 View Code

 

TUserDao.java类

 View Code

 

TUserService.java接口

 View Code

 

TUserServiceImpl.java

 View Code

 4.2.2 生成验证码的工具

验证码生产工具VerifyCodeUtil.java

 View Code

 

4.2.3 自定义用户信息类CustomUserDetails 集成实体类TUser并实现security提供的UserDetails 接口

UserDetails是真正用于构建SpringSecurity登录的安全用户(UserDetails),也就是说,在springsecurity进行用户认证的过程中,是通过UserDetails的实现类去获取用户信息,然后进行授权验证的。不明白?没关系,继续往下看
复制代码
 1 package com.shf.security.security.config;
 2 
 3 import com.shf.security.user.entity.TUser;
 4 import org.springframework.security.core.GrantedAuthority;
 5 import org.springframework.security.core.userdetails.UserDetails;
 6 
 7 import java.util.Collection;
 8 
 9 /**
10  * 描述:自定义UserDetails,使UserDetails具有TUser的实体结构
11  *
12  * @Author shf
13  * @Date 2019/4/19 10:30
14  * @Version V1.0
15  **/
16 public class CustomUserDetails extends TUser implements UserDetails {
17     public CustomUserDetails(TUser tUser){
18         if(null != tUser){
19             this.setId(tUser.getId());
20             this.setCode(tUser.getCode());
21             this.setCreateTime(tUser.getCreateTime());
22             this.setUpdateTime(tUser.getUpdateTime());
23             this.setUsername(tUser.getUsername());
24             this.setPassword(tUser.getPassword());
25             this.setIsDelete(tUser.getIsDelete());
26             this.setEmail(tUser.getEmail());
27             this.setPhone(tUser.getPhone());
28             this.setRole(tUser.getRole());
29         }
30     }
31     @Override
32     public Collection<? extends GrantedAuthority> getAuthorities() {
33         return null;
34     }
35 
36     @Override
37     public boolean isAccountNonExpired() {
38         return true;
39     }
40 
41     @Override
42     public boolean isAccountNonLocked() {
43         return true;
44     }
45 
46     @Override
47     public boolean isCredentialsNonExpired() {
48         return true;
49     }
50 
51     @Override
52     public boolean isEnabled() {
53         return true;
54     }
55 }
复制代码

 4.2.4 创建CustomUserDetailsService 类实现UserDetailsService接口

在下文将要提到的CustomAuthenticationProvider 类,也就是security核心的验证类中,会调用CustomUserDetailsService 中重写的loadUserByUsername方法

复制代码
 1 package com.shf.security.security.config;
 2 
 3 import com.shf.security.user.entity.TUser;
 4 import com.shf.security.user.service.TUserService;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.security.core.userdetails.UserDetails;
 7 import org.springframework.security.core.userdetails.UserDetailsService;
 8 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 9 import org.springframework.stereotype.Component;
10 
11 /**
12  * 描述:自定义UserDetailsService,从数据库读取用户信息,实现登录验证
13  *
14  * @Author shf
15  * @Date 2019/4/21 17:21
16  * @Version V1.0
17  **/
18 @Component
19 public class CustomUserDetailsService implements UserDetailsService {
20     @Autowired
21     private TUserService userService;
22 
23     /**
24      * 认证过程中 - 根据登录信息获取用户详细信息
25      *
26      * @param username 登录用户输入的用户名
27      * @return
28      * @throws UsernameNotFoundException
29      */
30     @Override
31     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
32         //根据用户输入的用户信息,查询数据库中已注册用户信息
33         TUser user = userService.findByName(username);
34         //如果用户不存在直接抛出UsernameNotFoundException异常
35         if (user == null) throw new UsernameNotFoundException("用户名为" + username + "的用户不存在");
36         return new CustomUserDetails(user);
37     }
38 }
复制代码

 

4.2.5 新建类CustomWebAuthenticationDetails继承WebAuthenticationDetails类

类似于UserDetails类给我们提供了用户详细信息一样,WebAuthenticationDetails则为我们提供了登录请求的用户的信息(也就是申请登录的用户的username和password信息),springsecurity默认只验证用户的username和password信息,所以我们如果想实现验证码登录,需要重写WebAuthenticationDetails类,使其能通过HttpServletRequest获取到用户输入的验证码的信息。

复制代码
 1 package com.shf.security.security.config;
 2 
 3 import org.springframework.security.web.authentication.WebAuthenticationDetails;
 4 
 5 import javax.servlet.http.HttpServletRequest;
 6 
 7 /**
 8  * 描述:自定义WebAuthenticationDetails,将验证码和用户名、密码一同带入AuthenticationProvider中
 9  *
10  * @Author shf
11  * @Date 2019/4/21 16:58
12  * @Version V1.0
13  **/
14 public class CustomWebAuthenticationDetails extends WebAuthenticationDetails {
15     private static final long serialVersionUID = 6975601077710753878L;
16     private final String verifyCode;
17     public CustomWebAuthenticationDetails(HttpServletRequest request) {
18         super(request);
19         verifyCode = request.getParameter("verifyCode");
20     }
21 
22     public String getVerifyCode() {
23         return verifyCode;
24     }
25 
26     @Override
27     public String toString() {
28         StringBuilder sb = new StringBuilder();
29         sb.append(super.toString()).append("; verifyCode: ").append(this.getVerifyCode());
30         return sb.toString();
31     }
32 }
复制代码

 

4.2.6 创建CustomAuthenticationDetailsSource类继承AuthenticationDetailsSource类

上面提到CustomWebAuthenticationDetails 需要通过HttpServletRequest获取到用户输入的验证码的信息。AuthenticationDetailsSource类就是初始化CustomWebAuthenticationDetails类的地方,在这里面我们需要将HttpServletRequest传递到CustomAuthenticationDetailsSource中。

复制代码
 1 package com.shf.security.security.config;
 2 
 3 import org.springframework.security.authentication.AuthenticationDetailsSource;
 4 import org.springframework.security.web.authentication.WebAuthenticationDetails;
 5 import org.springframework.stereotype.Component;
 6 
 7 import javax.servlet.http.HttpServletRequest;
 8 
 9 /**
10  * 描述:自定义AuthenticationDetailsSource,将HttpServletRequest注入到CustomWebAuthenticationDetails,使其能获取到请求中的验证码等其他信息
11  *
12  * @Author shf
13  * @Date 2019/4/21 17:03
14  * @Version V1.0
15  **/
16 @Component
17 public class CustomAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {
18     @Override
19     public WebAuthenticationDetails buildDetails(HttpServletRequest request) {
20         return new CustomWebAuthenticationDetails(request);
21     }
22 }
复制代码

 

4.2.7 实现自定义认证器(重点),创建CustomAuthenticationProvider继承AbstractUserDetailsAuthenticationProvider类

AbstractUserDetailsAuthenticationProvider类实现的是AuthenticationProvider接口

复制代码
  1 package com.shf.security.security.config;
  2 
  3 import com.shf.security.utils.VerifyCodeUtil;
  4 import lombok.extern.slf4j.Slf4j;
  5 import org.springframework.beans.factory.annotation.Autowired;
  6 import org.springframework.security.authentication.BadCredentialsException;
  7 import org.springframework.security.authentication.DisabledException;
  8 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  9 import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
 10 import org.springframework.security.core.Authentication;
 11 import org.springframework.security.core.AuthenticationException;
 12 import org.springframework.security.core.userdetails.UserDetails;
 13 import org.springframework.stereotype.Component;
 14 import org.springframework.web.context.request.RequestContextHolder;
 15 import org.springframework.web.context.request.ServletRequestAttributes;
 16 
 17 import javax.servlet.http.HttpServletRequest;
 18 import javax.servlet.http.HttpSession;
 19 
 20 /**
 21  * 描述:自定义SpringSecurity的认证器
 22  *
 23  * @Author shf
 24  * @Date 2019/4/21 17:30
 25  * @Version V1.0
 26  **/
 27 @Component
 28 @Slf4j
 29 public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {//implements AuthenticationProvider {
 30     @Autowired
 31     private CustomUserDetailsService userDetailsService;
 32 
 33     @Override
 34     protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
 35 
 36     }
 37 
 38     @Override
 39     public Authentication authenticate(Authentication authentication) throws AuthenticationException {
 40         //用户输入的用户名
 41         String username = authentication.getName();
 42         //用户输入的密码
 43         String password = authentication.getCredentials().toString();
 44         //通过CustomWebAuthenticationDetails获取用户输入的验证码信息
 45         CustomWebAuthenticationDetails details = (CustomWebAuthenticationDetails) authentication.getDetails();
 46         String verifyCode = details.getVerifyCode();
 47         if(null == verifyCode || verifyCode.isEmpty()){
 48             log.warn("未输入验证码");
 49             throw new NullPointerException("请输入验证码");
 50         }
 51         //校验验证码
 52         if(!validateVerifyCode(verifyCode)){
 53             log.warn("验证码输入错误");
 54             throw new DisabledException("验证码输入错误");
 55         }
 56         //通过自定义的CustomUserDetailsService,以用户输入的用户名查询用户信息
 57         CustomUserDetails userDetails = (CustomUserDetails) userDetailsService.loadUserByUsername(username);
 58         //校验用户密码
 59         if(!userDetails.getPassword().equals(password)){
 60             log.warn("密码错误");
 61             throw new BadCredentialsException("密码错误");
 62         }
 63         Object principalToReturn = userDetails;
 64         //将用户信息塞到SecurityContext中,方便获取当前用户信息
 65         return this.createSuccessAuthentication(principalToReturn, authentication, userDetails);
 66     }
 67 
 68     @Override
 69     protected UserDetails retrieveUser(String s, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
 70         return null;
 71     }
 72 
 73     /**
 74      * 验证用户输入的验证码
 75      * @param inputVerifyCode
 76      * @return
 77      */
 78     public boolean validateVerifyCode(String inputVerifyCode){
 79         //获取当前线程绑定的request对象
 80         HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
 81         // 这个VerifyCodeFactory.SESSION_KEY是在servlet中存入session的名字
 82         HttpSession session = request.getSession();
 83         String verifyCode = (String)session.getAttribute(VerifyCodeUtil.SESSION_KEY);
 84         if(null == verifyCode || verifyCode.isEmpty()){
 85             log.warn("验证码过期请重新验证");
 86             throw new DisabledException("验证码过期,请重新验证");
 87         }
 88         // 不分区大小写
 89         verifyCode = verifyCode.toLowerCase();
 90         inputVerifyCode = inputVerifyCode.toLowerCase();
 91 
 92         log.info("验证码:{}, 用户输入:{}", verifyCode, inputVerifyCode);
 93 
 94         return verifyCode.equals(inputVerifyCode);
 95     }
 96 
 97     @Override
 98     public boolean supports(Class<?> authentication) {
 99         return authentication.equals(UsernamePasswordAuthenticationToken.class);
100     }
101 }
复制代码

 

如上图所示,AuthenticationProvider接口为我们提供了security核心的认证方法authenticate方法,该方法就是实现用户认证的方法。我们自定义实现authenticate方法,大致思路如下,通过CustomWebAuthenticationDetails获取到用户输入的username,password,verifyCode信息。通过CustomUserDetails 中获取用户信息(数据库中注册的用户的信息),然后对用户信息进行比对认证。最终实现认证过程。

当然,也可以直接实现AuthenticationProvider 接口,然后实现authenticate方法。这都是可以的但是有现成的AbstractUserDetailsAuthenticationProvider可用,为啥还要再写一遍呢?尤其是AbstractUserDetailsAuthenticationProvider类提供的createSuccessAuthentication方法,封装了一个完美的Authentication(后续会继续提到)。AuthenticationProvider 的supports方法呢是直接决定哪一个AuthenticationProvider 的实现类是我们需要的认证器。

 

4.2.8 创建WebSecurityConfig 继承WebSecurityConfigurerAdapter配置类。(spring security的配置类)

具体看代码注释吧,很详细的。

值得一提的是第81行的配置,是我们实现ajax登录的关键。

 

复制代码
  1 package com.shf.security.security.config;
  2 
  3 import lombok.extern.slf4j.Slf4j;
  4 import org.springframework.beans.factory.annotation.Autowired;
  5 import org.springframework.context.annotation.Bean;
  6 import org.springframework.context.annotation.Configuration;
  7 import org.springframework.security.authentication.AuthenticationDetailsSource;
  8 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  9 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 10 import org.springframework.security.config.annotation.web.builders.WebSecurity;
 11 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 12 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 13 import org.springframework.security.core.Authentication;
 14 import org.springframework.security.core.AuthenticationException;
 15 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 16 import org.springframework.security.crypto.password.PasswordEncoder;
 17 import org.springframework.security.web.authentication.AuthenticationFailureHandler;
 18 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
 19 import org.springframework.security.web.authentication.WebAuthenticationDetails;
 20 import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
 21 
 22 import javax.servlet.ServletException;
 23 import javax.servlet.http.HttpServletRequest;
 24 import javax.servlet.http.HttpServletResponse;
 25 import java.io.IOException;
 26 import java.io.PrintWriter;
 27 
 28 /**
 29  * 描述:
 30  *
 31  * @Author shf
 32  * @Date 2019/4/19 10:54
 33  * @Version V1.0
 34  **/
 35 @Configuration
 36 @EnableWebSecurity
 37 @Slf4j
 38 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 39     @Autowired
 40     private CustomAuthenticationProvider customAuthenticationProvider;
 41 
 42     @Autowired
 43     private CustomUserDetailsService customUserDetailsService;
 44 
 45     @Autowired
 46     private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource;
 47 
 48     @Override
 49     protected void configure(AuthenticationManagerBuilder auth) throws Exception {
 50         //将自定义的CustomAuthenticationProvider装配到AuthenticationManagerBuilder
 51         auth.authenticationProvider(customAuthenticationProvider);
 52         //将自定的CustomUserDetailsService装配到AuthenticationManagerBuilder
 53         auth.userDetailsService(customUserDetailsService).passwordEncoder(new PasswordEncoder() {
 54             @Override
 55             public String encode(CharSequence charSequence) {
 56                 return charSequence.toString();
 57             }
 58 
 59             @Override
 60             public boolean matches(CharSequence charSequence, String s) {
 61                 return s.equals(charSequence.toString());
 62             }
 63         });
 64     }
 65     @Override
 66     public void configure(HttpSecurity http) throws Exception {
 67         http
 68                 .cors()
 69                 .and().csrf().disable();//开启跨域
 70         http    /*匿名请求:不需要进行登录拦截的url*/
 71                 .authorizeRequests()
 72                     .antMatchers("/getVerifyCode").permitAll()
 73                     .anyRequest().authenticated()//其他的路径都是登录后才可访问
 74                     .and()
 75                 /*登录配置*/
 76                 .formLogin()
 77                     .loginPage("/login_page")//登录页,当未登录时会重定向到该页面
 78                     .successHandler(authenticationSuccessHandler())//登录成功处理
 79                     .failureHandler(authenticationFailureHandler())//登录失败处理
 80                     .authenticationDetailsSource(authenticationDetailsSource)//自定义验证逻辑,增加验证码信息
 81                     .loginProcessingUrl("/login")//restful登录请求地址
 82                     .usernameParameter("username")//默认的用户名参数
 83                     .passwordParameter("password")//默认的密码参数
 84                     .permitAll()
 85                     .and()
 86                 /*登出配置*/
 87                 .logout()
 88                     .permitAll()
 89                     .logoutSuccessHandler(logoutSuccessHandler());
 90     }
 91 
 92     /**
 93      * security检验忽略的请求,比如静态资源不需要登录的可在本处配置
 94      * @param web
 95      */
 96     @Override
 97     public void configure(WebSecurity web){
 98 //        platform.ignoring().antMatchers("/");
 99     }
100 
101     @Autowired
102     public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
103         auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
104         auth.eraseCredentials(false);
105     }
106     //密码加密配置
107     @Bean
108     public BCryptPasswordEncoder passwordEncoder() {
109         return new BCryptPasswordEncoder(4);
110     }
111     //登入成功
112     @Bean
113     public AuthenticationSuccessHandler authenticationSuccessHandler() {
114         return new AuthenticationSuccessHandler() {
115             /**
116              * 处理登入成功的请求
117              *
118              * @param httpServletRequest
119              * @param httpServletResponse
120              * @param authentication
121              * @throws IOException
122              * @throws ServletException
123              */
124             @Override
125             public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
126                 httpServletResponse.setContentType("application/json;charset=utf-8");
127                 PrintWriter out = httpServletResponse.getWriter();
128                 out.write("{\"status\":\"success\",\"msg\":\"登录成功\"}");
129                 out.flush();
130                 out.close();
131             }
132         };
133     }
134     //登录失败
135     @Bean
136     public AuthenticationFailureHandler authenticationFailureHandler(){
137         return new AuthenticationFailureHandler() {
138             /**
139              * 处理登录失败的请求
140              * @param httpServletRequest
141              * @param httpServletResponse
142              * @param e
143              * @throws IOException
144              * @throws ServletException
145              */
146             @Override
147             public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
148                 httpServletResponse.setContentType("application/json;charset=utf-8");
149                 PrintWriter out = httpServletResponse.getWriter();
150                 out.write("{\"status\":\"error\",\"msg\":\"登录失败\"}");
151                 out.flush();
152                 out.close();
153             }
154         };
155     }
156     //登出处理
157     @Bean
158     public LogoutSuccessHandler logoutSuccessHandler() {
159         return new LogoutSuccessHandler() {
160             /**
161              * 处理登出成功的请求
162              *
163              * @param httpServletRequest
164              * @param httpServletResponse
165              * @param authentication
166              * @throws IOException
167              * @throws ServletException
168              */
169             @Override
170             public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
171                 httpServletResponse.setContentType("application/json;charset=utf-8");
172                 PrintWriter out = httpServletResponse.getWriter();
173                 out.write("{\"status\":\"success\",\"msg\":\"登出成功\"}");
174                 out.flush();
175                 out.close();
176             }
177         };
178     }
179 }
复制代码

 

 

4.2.9 LoginController

 View Code

 

 4.2.10 UserHolder 工具类

在日常的业务中,在很多业务代码中,我们都需要获取当前用户的信息。这个类就是一个静态工具类。

复制代码
 1 package com.shf.security.utils;
 2 
 3 import com.shf.security.user.entity.TUser;
 4 import org.springframework.security.core.Authentication;
 5 import org.springframework.security.core.context.SecurityContext;
 6 import org.springframework.security.core.context.SecurityContextHolder;
 7 
 8 /**
 9  * 描述:
10  *
11  * @Author shf
12  * @Description TODO
13  * @Date 2019/4/21 15:24
14  * @Version V1.0
15  **/
16 public class UserHolder {
17     public static TUser getUserDetail(){
18         SecurityContext ctx = SecurityContextHolder.getContext();
19         Authentication auth = ctx.getAuthentication();
20         TUser user = (TUser) auth.getPrincipal();
21         return user;
22     }
23     public static String getUserCode(){
24         SecurityContext ctx = SecurityContextHolder.getContext();
25         Authentication auth = ctx.getAuthentication();
26         TUser user = (TUser) auth.getPrincipal();
27         return user.getCode();
28     }
29     public static int getUserId(){
30         SecurityContext ctx = SecurityContextHolder.getContext();
31         Authentication auth = ctx.getAuthentication();
32         TUser user = (TUser) auth.getPrincipal();
33         return user.getId();
34     }
35 }
复制代码

 4.2.10 其他工具类Response.java

 View Code

 

五、问题总结

5.1 验证码问题

其实呢通过第二部分对security原理的分析,我们不难看出,spring security就是建立在一连串的过滤器filter上的,spring security通过这些过滤器逐层对请求进行过滤,然后进行各种登录认证和授权过程。说道这里估计大家也就能想到另外的实现验证码验证登录的方式。也就是在认证用户输入的用户名和密码之前验证验证码信息。UsernamePasswordAuthenticationFilter过滤器顾名思义就是用户名和密码的过滤器。所以我们只需要在4.2.8 章节中的WebSecurityConfig中addFilterBefore()配置在UsernamePasswordAuthenticationFilter过滤器之前执行VerifyCodeFilter过滤器。然后在VerifyCodeFilter过滤器中执行验证码的验证逻辑即可。

1 .and()
2 .addFilterBefore(new VerifyCodeFilter(),UsernamePasswordAuthenticationFilter.class)

 

但是这种方式呢有一种天然的缺点,也就是没法办将除username和password的信息带到认证器中进行统一认证。而且如果我们除了验证码意外还需要验证更多的信息的话。岂不是要写n多个filter。

5.2  貌似忘了进行测试登录

浏览器请求:http://localhost:8080/user/test

结果:

正是我们想要的结果。

登录验证还是使用postman吧,因为spring security默认只处理post方式的登录请求。浏览器提交restful请求默认是get的。所以。。。

postman请求验证码

 postman登录

 

看到这里如果还有问题,请移步https://github.com/hello-shf/spring-security.git开箱即用。

如有问题或者错误的地方,还请留言指出。

 

 

 

小小的码农,大大的梦想
 
 
转载自:https://www.cnblogs.com/hello-shf/p/10800457.html#commentform

posted on 2020-11-05 10:59  edson_sir  阅读(1100)  评论(0)    收藏  举报

导航