好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Spring Security添加验证码的两种方式小结

一、自定义认证逻辑

生成验证码工具

?

1

2

3

4

5

< dependency >

     < groupId >com.github.penggle</ groupId >

     < artifactId >kaptcha</ artifactId >

     < version >2.3.2</ version >

</ dependency >

添加Kaptcha配置

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

@Configuration

public class KaptchaConfig {

     @Bean

     Producer kaptcha() {

         Properties properties = new Properties();

         properties.setProperty( "kaptcha.image.width" , "150" );

         properties.setProperty( "kaptcha.image.height" , "50" );

         properties.setProperty( "kaptcha.textproducer.char.string" , "0123456789" );

         properties.setProperty( "kaptcha.textproducer.char.length" , "4" );

         Config config = new Config(properties);

         DefaultKaptcha defaultKaptcha = new DefaultKaptcha();

         defaultKaptcha.setConfig(config);

         return defaultKaptcha;

     }

}

生成验证码文本,放入HttpSession中

根据验证码文本生成图片 通过IO流写出到前端。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

@RestController

public class LoginController {

     @Autowired

     Producer producer;

     @GetMapping ( "/vc.jpg" )

     public void getVerifyCode(HttpServletResponse resp, HttpSession session) throws IOException {

         resp.setContentType( "image/jpeg" );

         String text = producer.createText();

         session.setAttribute( "kaptcha" , text);

         BufferedImage image = producer.createImage(text);

         try (ServletOutputStream out = resp.getOutputStream()) {

             ImageIO.write(image, "jpg" , out);

         }

     }

     @RequestMapping ( "/index" )

     public String index() {

         return "login success" ;

     }

     @RequestMapping ( "/hello" )

     public String hello() {

         return "hello spring security" ;

     }

}

form表单

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

<!DOCTYPE html>

< html lang = "en" xmlns:th = "http://www.thymeleaf.org" >

< head >

     < meta charset = "UTF-8" >

     < title >登录</ title >

     < link href = "//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel = "external nofollow"   rel = "stylesheet" id = "bootstrap-css" >

     < script src = "//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" ></ script >

     < script src = "//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" ></ script >

</ head >

< style >

     #login .container #login-row #login-column #login-box {

         border: 1px solid #9C9C9C;

         background-color: #EAEAEA;

     }

</ style >

< body >

< div id = "login" >

     < div class = "container" >

         < div id = "login-row" class = "row justify-content-center align-items-center" >

             < div id = "login-column" class = "col-md-6" >

                 < div id = "login-box" class = "col-md-12" >

                     < form id = "login-form" class = "form" action = "/doLogin" method = "post" >

                         < h3 class = "text-center text-info" >登录</ h3 >

                         < div th:text = "${SPRING_SECURITY_LAST_EXCEPTION}" ></ div >

                         < div class = "form-group" >

                             < label for = "username" class = "text-info" >用户名:</ label >< br >

                             < input type = "text" name = "uname" id = "username" class = "form-control" >

                         </ div >

                         < div class = "form-group" >

                             < label for = "password" class = "text-info" >密码:</ label >< br >

                             < input type = "text" name = "passwd" id = "password" class = "form-control" >

                         </ div >

                         < div class = "form-group" >

                             < label for = "kaptcha" class = "text-info" >验证码:</ label >< br >

                             < input type = "text" name = "kaptcha" id = "kaptcha" class = "form-control" >

                             < img src = "/vc.jpg" alt = "" >

                         </ div >

                         < div class = "form-group" >

                             < input type = "submit" name = "submit" class = "btn btn-info btn-md" value = "登录" >

                         </ div >

                     </ form >

                 </ div >

             </ div >

         </ div >

     </ div >

</ div >

</ body >

验证码图片地址为我们在Controller中定义的验证码接口地址。

身份认证是AuthenticationProvider的authenticate方法完成,因此验证码可以在此之前完成:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

public class KaptchaAuthenticationProvider extends DaoAuthenticationProvider {

 

     @Override

     public Authentication authenticate(Authentication authentication) throws AuthenticationException {

         HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

         String kaptcha = req.getParameter( "kaptcha" );

         String sessionKaptcha = (String) req.getSession().getAttribute( "kaptcha" );

         if (kaptcha != null && sessionKaptcha != null && kaptcha.equalsIgnoreCase(sessionKaptcha)) {

             return super .authenticate(authentication);

         }

         throw new AuthenticationServiceException( "验证码输入错误" );

     }

}

配置AuthenticationManager:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

@Configuration

public class SecurityConfig extends WebSecurityConfigurerAdapter {

 

     @Bean

     AuthenticationProvider kaptchaAuthenticationProvider() {

         InMemoryUserDetailsManager users = new InMemoryUserDetailsManager(User.builder()

                 .username( "xiepanapn" ).password( "{noop}123" ).roles( "admin" ).build());

         KaptchaAuthenticationProvider provider = new KaptchaAuthenticationProvider();

         provider.setUserDetailsService(users);

         return provider;

     }

 

     @Override

     @Bean

     public AuthenticationManager authenticationManagerBean() throws Exception {

         ProviderManager manager = new ProviderManager(kaptchaAuthenticationProvider());

         return manager;

     }

 

     @Override

     protected void configure(HttpSecurity http) throws Exception {

         http.authorizeRequests()

                 .antMatchers( "/vc.jpg" ).permitAll()

                 .anyRequest().authenticated()

                 .and()

                 .formLogin()

                 .loginPage( "/mylogin.html" )

                 .loginProcessingUrl( "/doLogin" )

                 .defaultSuccessUrl( "/index.html" )

                 .failureForwardUrl( "/mylogin.html" )

                 .usernameParameter( "uname" )

                 .passwordParameter( "passwd" )

                 .permitAll()

                 .and()

                 .csrf().disable();

     }

}

配置UserDetailsService提供的数据源 提供AuthenticationProvider实例并配置UserDetailsService 重写authenticationManagerBean方法提供一个自己的ProviderManager并自定义AuthenticationManager实例。

二、自定义过滤器

LoginFilter继承UsernamePasswordAuthenticationFilter 重写attemptAuthentication方法:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

public class LoginFilter extends UsernamePasswordAuthenticationFilter {

 

     @Override

     public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

         if (!request.getMethod().equals( "POST" )) {

             throw new AuthenticationServiceException(

                     "Authentication method not supported: " + request.getMethod());

         }

         String kaptcha = request.getParameter( "kaptcha" );

         String sessionKaptcha = (String) request.getSession().getAttribute( "kaptcha" );

         if (!StringUtils.isEmpty(kaptcha) && !StringUtils.isEmpty(sessionKaptcha) && kaptcha.equalsIgnoreCase(sessionKaptcha)) {

             return super .attemptAuthentication(request, response);

         }

         throw new AuthenticationServiceException( "验证码输入错误" );

     }

}

在SecurityConfig中配置LoginFilter

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

@Configuration

public class SecurityConfig extends WebSecurityConfigurerAdapter {

     @Override

     protected void configure(AuthenticationManagerBuilder auth)

             throws Exception {

         auth.inMemoryAuthentication()

                 .withUser( "javaboy" )

                 .password( "{noop}123" )

                 .roles( "admin" );

     }

 

     @Override

     @Bean

     public AuthenticationManager authenticationManagerBean()

             throws Exception {

         return super .authenticationManagerBean();

     }

 

     @Bean

     LoginFilter loginFilter() throws Exception {

         LoginFilter loginFilter = new LoginFilter();

         loginFilter.setFilterProcessesUrl( "/doLogin" );

         loginFilter.setAuthenticationManager(authenticationManagerBean());

         loginFilter.setAuthenticationSuccessHandler( new SimpleUrlAuthenticationSuccessHandler( "/hello" ));

         loginFilter.setAuthenticationFailureHandler( new SimpleUrlAuthenticationFailureHandler( "/mylogin.html" ));

         return loginFilter;

     }

 

     @Override

     protected void configure(HttpSecurity http) throws Exception {

         http.authorizeRequests()

                 .antMatchers( "/vc.jpg" ).permitAll()

                 .anyRequest().authenticated()

                 .and()

                 .formLogin()

                 .loginPage( "/mylogin.html" )

                 .permitAll()

                 .and()

                 .csrf().disable();

         http.addFilterAt(loginFilter(),

                 UsernamePasswordAuthenticationFilter. class );

     }

}

显然第二种比较简单

总结

到此这篇关于Spring Security添加验证码的两种方式的文章就介绍到这了,更多相关Spring Security添加验证码内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

原文链接:https://juejin.cn/post/7016269020861038623

查看更多关于Spring Security添加验证码的两种方式小结的详细内容...

  阅读:17次