security实现账密、手机号和微信三种方式登陆

:security实现多种方式登陆

spring security 的核心功能主要包括
认证
授权
攻击防护
其核心就是一组过滤器链,项目启动后将会自动配置。最核心的就是 Basic Authentication Filter 用来认证用户的身份,一个在spring security中一种过滤器处理一种认证方式。


在说多种认证方式之前,咱们先简单过下单认证方式是如何配置的,也说下Spring Security的各个配置类的作用。

1、UsernamePasswordAuthenticationFilter
Spring Security 默认认证过滤器,处于拦截器链当中,继承AbstractAuthenticationProcessingFilter,咱们看一下源码
在这里插入图片描述
在这里插入图片描述
可以看出里面构造方法指定了默认拦截地址 /login,attemptAuthentication是父类AbstractAuthenticationProcessingFilter抽象方法的实现方法,在父类中doFilter方法里调用,可以看到方法实现是从request里取得用户名密码,最后构建成UsernamePasswordAuthenticationToken,然后调用AuthenticationManager的 authenticate 方法作为参数传进去进行认证。
2、UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken没什么好讲的,在其实就是对认证参数用户名密码的封装,当然后续登录成功之后会作为用户认证信息的封装。
3、AuthenticationManager
authenticationManager是AbstractAuthenticationProcessingFilter的一个成员变量,从上面可以看出,这个参数是必须赋值的,采用默认的过滤器认证,spring security会默认给一个实现类ProviderManager,看下代码
在这里插入图片描述
在这里插入图片描述
从源码看到,管理器会遍历所有注册的认证器集合,调用每个认证器的authenticate认证,此时会有疑惑,如果多个登录方式,肯定会有多个认证器,每次都遍历认证所有的认证器是否不太合理?关键在于以下这个判断代码

这个 toTest 参数就是过滤器传进来的 UsernamePasswordAuthenticationToken

Class<? extends Authentication> toTest = authentication.getClass();
 
if (!provider.supports(toTest)) {
     continue;
}

在这里插入图片描述
会调用每个认证器的supports方法,只有此方法返回true,才会执行认证,(由此想到如果自定义认证器,此方法一定要重写),此方法如何实现,咱们看一下此方法的默认实现,会判断

public boolean supports(Class<?> authentication) {
        return (UsernamePasswordAuthenticationToken.class
                .isAssignableFrom(authentication));
  }

由此看出,参数必须为 UsernamePasswordAuthenticationToken 类或者其子类的字节码,此参数又是由UsernamePasswordAuthenticationFilter 里传过来的

由此得知,每个过滤器都需要一个AbstractAuthenticationToken的子类绑定
4、AuthenticationProvider
这个是重点配置,具体认证方法都是在这里实现的,因此我们要自定义我们的认证方法,都需要实现这个接口,这个接口只有两个方法,authenticate用来认证,supports 用来决定启用条件
具体实现方法根据自己的业务需要,一般是查询数据库,对比密码,看下我的实现类,一般我们会注入一个自定义的UserDetailService实现类,重写 loadUserByUsername,具体根据用户名查询用户信息,认证成功将用户信息包装成 Authentication 返回
5、AuthenticationSuccessHandler、AuthenticationFailureHandler
看过滤器源码,认证结束后,会根据认证成功或失败,分别调用两个成功失败处理器

successHandler.onAuthenticationSuccess(request, response, authResult);

failureHandler.onAuthenticationFailure(request, response, failed);

因此,我们可以自定义这两个处理器,来自己处理认证成功失败
6、配置文件
最后,Spring Security的配置文件

根据上面的介绍和代码,我们大概可以知道原理了,现在开始撸码吧!

pom文件添加security的依赖
${spring-boot.version} 2.3.1.RELEASE

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>

实现UsernamePasswordAuthenticationFilter
该步骤作为过滤器适用,根据判断是否存在对应session,以提示是否需要重新登陆


@Slf4j
public class LoginFilter extends UsernamePasswordAuthenticationFilter {
    private static final List<String> forIndexList = Lists.newArrayList();

    static {
        forIndexList.add("/");
    }


    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        //根路径,直接跳转到index页面
        if (forIndexList.contains(request.getServletPath())) {
            response.sendRedirect(request.getRequestURL() + "index.html");
            return;
        }
        log.info("===>URL={} , IP={}", request.getRequestURL(), request.getRemoteAddr());

        // 如果是接口请求验证登录情况
        if (!request.getRequestURL().toString().contains(".html")
                && !"/login".equals(request.getServletPath())
                && !"/mobileLogin".equals(request.getServletPath())
                && !"/wxLogin".equals(request.getServletPath())) {
            //用户是否登录
            LoginUserDetail currentUser = SessionUtils.getCurrentUser(request);
            log.info("current user {}", JSON.toJSONString(currentUser));
            if (currentUser == null) {
                response.setContentType("application/json;charset=UTF-8");
                PrintWriter printWriter = response.getWriter();
                Response httpResponse = new Response(401, "请先登录!");
                printWriter.write(JSON.toJSONString(httpResponse));
                printWriter.flush();
                printWriter.close();
                return;
            }
        }
        chain.doFilter(request, response);
    }
}

实现UserDetails,作为session的信息实体

public class LoginUserDetail implements UserDetails, Serializable {

    private Long id;
    private String username;
    private String password;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

登陆方式1:账号密码登陆

public class UsernameAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
    public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
    public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";

    private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
    private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
    private boolean postOnly = true;

    public UsernameAuthenticationProcessingFilter() {
        super(new AntPathRequestMatcher("/login", "POST"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }
        String code = request.getParameter("code");
        String kaptchaCode = (String) request.getSession().getAttribute("verificationCode");
        if(StringUtils.isEmpty(code)) {
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(500);
            PrintWriter printWriter = response.getWriter();
            Response httpResponse = new Response(500,"请填写验证码!");
            printWriter.write(new ObjectMapper().writeValueAsString(httpResponse));
            printWriter.flush();
            printWriter.close();
            throw new AuthenticationServiceException("请填写验证码");
        }else if(!kaptchaCode.toLowerCase().equals(code.toLowerCase())) {
            logger.info("goto===>验证码错误");
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(500);
            PrintWriter printWriter = response.getWriter();
            Response httpResponse = new Response(500,"验证码错误!");
            printWriter.write(new ObjectMapper().writeValueAsString(httpResponse));
            printWriter.flush();
            printWriter.close();
            throw new AuthenticationServiceException("验证码错误");
        }
        // 用户名称
        String loginAcct = obtainUsername(request);
        if (StringUtils.isEmpty(loginAcct)) {
            throw new AuthenticationServiceException("登录账号不能为空");
        }
        // 密码
        String password = obtainPassword(request);
        if (StringUtils.isEmpty(password)) {
            throw new AuthenticationServiceException("密码不能为空");
        }

        return this.getAuthenticationManager().authenticate(new UsernameAuthenticationToken(loginAcct, password));
    }


    protected String obtainUsername(HttpServletRequest request) {
        return request.getParameter(usernameParameter);
    }

    protected String obtainPassword(HttpServletRequest request) {
        return request.getParameter(passwordParameter);
    }

}
public class UsernameAuthenticationProvider implements AuthenticationProvider {
    protected Log logger = LogFactory.getLog(getClass());
    // 自定义查询用户信息
    @Autowired
    @Qualifier("userDetailsServiceImpl")
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        try {
            UsernameAuthenticationToken tokenReq = (UsernameAuthenticationToken) authentication;

            //todo 根据手机号码,查找登录人信息....
            UserDetails userDetails = userDetailsService.loadUserByUsername(tokenReq.getUsername());

            //todo 密码加密后比较是否匹配
            if(!passwordEncoder.matches(tokenReq.getPassword(), userDetails.getPassword())) {
                throw new BadCredentialsException("账号或者密码错误");
            }
            return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        } catch (BadCredentialsException | UsernameNotFoundException e) {
            logger.error(e.getMessage());
            throw e;
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new BadCredentialsException("登录异常");
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return (UsernameAuthenticationToken.class.isAssignableFrom(authentication));
    }

}

public class UsernameAuthenticationToken extends AbstractAuthenticationToken {


    private String username;
    private String password;
    private String code;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public UsernameAuthenticationToken(String username, String password) {
        super(null);
        this.username = username;
        this.password = password;
    }

    @Override
    public Object getCredentials() {
        return null;
    }

    @Override
    public Object getPrincipal() {
        return null;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

public class MobileUserDetailsServiceImpl implements org.springframework.security.core.userdetails.UserDetailsService {

    @SneakyThrows
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// 自定义查询用户信息
        return new LoginUserDetail();
    }
}

登陆方式2:手机号登陆

本人使用了阿里云短信验证码,openId和unionId为微信登陆做准备

public class MobileCodeAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {

    public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "mobile";
    public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "code";

    private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
    private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;

    public static final String SPRING_SECURITY_FORM_UNION_KEY = "unionId";
    public static final String SPRING_SECURITY_FORM_OPEN_KEY = "openId";

    private String unionParameter = SPRING_SECURITY_FORM_UNION_KEY;
    private String openParameter = SPRING_SECURITY_FORM_OPEN_KEY;
    private boolean postOnly = true;

    public MobileCodeAuthenticationProcessingFilter() {
        super(new AntPathRequestMatcher("/mobileLogin", "POST"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }
        // 电话号码
        String mobile = obtainUsername(request);
        if (StringUtils.isEmpty(mobile)) {
            throw new AuthenticationServiceException("电话号码不能为空");
        }
        // 验证码
        String code = obtainPassword(request);
        if (StringUtils.isEmpty(code)) {
            throw new AuthenticationServiceException("验证码不能为空");
        }
        return this.getAuthenticationManager().authenticate(new MobileCodeAuthenticationToken(mobile, code, obtainUnionId(request), obtainOpenId(request)));
    }


    protected String obtainUsername(HttpServletRequest request) {
        return request.getParameter(usernameParameter);
    }

    protected String obtainPassword(HttpServletRequest request) {
        return request.getParameter(passwordParameter);
    }

    protected String obtainUnionId(HttpServletRequest request) {
        return request.getParameter(unionParameter);
    }

    protected String obtainOpenId(HttpServletRequest request) {
        return request.getParameter(openParameter);
    }
}

@Slf4j
public class MobileCodeAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
    protected Log logger = LogFactory.getLog(getClass());

    @Autowired
    @Qualifier("mobileUserDetailsServiceImpl")
    private UserDetailsService userDetailsService;
    @DubboReference
    ISysUserService sysUserService;
    @DubboReference
    ISmsCodeService smsCodeService;
    @DubboReference
    IUserWxService userWxService;

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {

    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        MobileCodeAuthenticationToken tokenReq = (MobileCodeAuthenticationToken) authentication;
        log.info("Method:authenticate. tokenReq:{}", FastJsonUtils.convertObjectToJSON(tokenReq));
        try {
            SysUser sysUser = sysUserService.findUserByMobile(tokenReq.getMobile());
            if (sysUser == null) {
                throw new BadCredentialsException("用户不存在");
            }
            SmsCode smsCode = smsCodeService.getSmsCode(tokenReq.getMobile(), SmsCodeUserType.B.getId());
            if (smsCode == null) {
                throw new BadCredentialsException("请获取验证码");
            }
            if (LocalDateTime.now().isAfter(smsCode.getModifyTime().plusMinutes(5))) {
                throw new BadCredentialsException("验证码已过期,请重新获取验证码");
            }
            // 校验验证码是否匹配
            if (!tokenReq.getCode().equals(smsCode.getCode())) {
                throw new BadCredentialsException("验证码不正确,请检查后重新输入");
            }
            // 根据手机号码,获取登录账号
            UserDetails userDetails = userDetailsService.loadUserByUsername(smsCode.getUserId().toString());
            if (StringUtils.isNotBlank(tokenReq.getUnionId())) {
                UserWx userWx = userWxService.findByUnionId(tokenReq.getUnionId());
                if (userWx == null) {
                    userWxService.createUserWx(UserWx.builder().userId(smsCode.getUserId()).unionId(tokenReq.getUnionId()).openId(tokenReq.getOpenId()).build());
                } else {
                    userWx.setOpenId(tokenReq.getOpenId());
                    userWx.setUnionId(tokenReq.getUnionId());
                    userWx.setUserId(smsCode.getUserId());
                    userWxService.updateUserWx(userWx);
                }
            }
            return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        } catch (BadCredentialsException | UsernameNotFoundException e) {
            logger.error(e.getMessage());
            throw e;
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new BadCredentialsException("手机验证码登录异常");
        }
    }

    @Override
    protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        return null;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return (MobileCodeAuthenticationToken.class.isAssignableFrom(authentication));
    }
public class MobileCodeAuthenticationToken extends AbstractAuthenticationToken {


    private String mobile;
    private String code;
    private String unionId;
    private String openId;

    public String getUnionId() {
        return unionId;
    }

    public void setUnionId(String unionId) {
        this.unionId = unionId;
    }

    public String getOpenId() {
        return openId;
    }

    public void setOpenId(String openId) {
        this.openId = openId;
    }

    public MobileCodeAuthenticationToken(String mobile, String code) {
        super(null);
        this.mobile = mobile;
        this.code = code;
    }

    public MobileCodeAuthenticationToken(String mobile, String code, String unionId, String openId) {
        super(null);
        this.mobile = mobile;
        this.code = code;
        this.unionId = unionId;
        this.openId = openId;
    }

    @Override
    public Object getCredentials() {
        return null;
    }

    @Override
    public Object getPrincipal() {
        return null;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}
@Service
@Slf4j
public class MobileUserDetailsServiceImpl implements org.springframework.security.core.userdetails.UserDetailsService 

    @SneakyThrows
    @Override
    public UserDetails loadUserByUsername(String phone) throws UsernameNotFoundException {
		// 自定义返回结果
        return new UserDetails();
    }
}

登陆方式3:微信登陆

对接微信扫码登陆文档可参考https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
微信登陆流程如下
在这里插入图片描述

public class WxAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {

    public static final String SPRING_SECURITY_FORM_UNION_KEY = "unionId";
    public static final String SPRING_SECURITY_FORM_OPEN_KEY = "openId";

    private String unionParameter = SPRING_SECURITY_FORM_UNION_KEY;
    private String openParameter = SPRING_SECURITY_FORM_OPEN_KEY;
    private boolean postOnly = true;

    public WxAuthenticationProcessingFilter() {
        super(new AntPathRequestMatcher("/wxLogin", "POST"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }
        // unionId
        String unionId = obtainUnion(request);
        if (StringUtils.isEmpty(unionId)) {
            throw new AuthenticationServiceException("unionId不能为空");
        }
        // openId
        String openId = obtainOpen(request);
        return this.getAuthenticationManager().authenticate(new WxAuthenticationToken(unionId, openId));
    }


    protected String obtainUnion(HttpServletRequest request) {
        return request.getParameter(unionParameter);
    }

    protected String obtainOpen(HttpServletRequest request) {
        return request.getParameter(openParameter);
    }


}
@Slf4j
public class WxAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
    protected Log logger = LogFactory.getLog(getClass());

    @Autowired
    @Qualifier("mobileUserDetailsServiceImpl")
    private UserDetailsService userDetailsService;
    @DubboReference
    IUserWxService userWxService;

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {

    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        WxAuthenticationToken tokenReq = (WxAuthenticationToken) authentication;
        try {
            UserWx userWx = userWxService.findByUnionId(tokenReq.getUnionId());
            if (userWx == null) {
                throw new BadCredentialsException("微信账号未绑定");
            }
            UserDetails userDetails = userDetailsService.loadUserByUsername(userWx.getUserId().toString());
            log.info("Method:authenticate. userDetails:{}", FastJsonUtils.convertObjectToJSON(userDetails));
            return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        } catch (BadCredentialsException | UsernameNotFoundException e) {
            log.error("Method:authenticate. Exception:", e);
            throw e;
        } catch (Exception e) {
            log.error("Method:authenticate. Exception:", e);
            throw new BadCredentialsException("微信登录异常");
        }
    }

    @Override
    protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        return null;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return (WxAuthenticationToken.class.isAssignableFrom(authentication));
    }

}
public class WxAuthenticationToken extends AbstractAuthenticationToken {
    
    private String unionId;


    private String openId;

    public String getUnionId() {
        return unionId;
    }

    public void setUnionId(String unionId) {
        this.unionId = unionId;
    }

    public String getOpenId() {
        return openId;
    }

    public void setOpenId(String openId) {
        this.openId = openId;
    }

    public WxAuthenticationToken(String unionId, String openId) {
        super(null);
        this.unionId = unionId;
        this.openId = openId;
    }

    @Override
    public Object getCredentials() {
        return null;
    }

    @Override
    public Object getPrincipal() {
        return null;
    }

}

最后进行security的配置

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

      @Autowired
      LoginAuthenticationEntryPoint loginAuthenticationEntryPoint;  //  未登陆时返回 JSON 格式的数据给前端(否则为 html)

      @Autowired
      LoginAuthenticationSuccessHandler loginAuthenticationSuccessHandler;  // 登录成功返回的 JSON 格式数据给前端(否则为 html)

      @Autowired
      LoginAuthenticationFailureHandler loginAuthenticationFailureHandler;  //  登录失败返回的 JSON 格式数据给前端(否则为 html)

      @Autowired
      LoginLogoutSuccessHandler loginlogoutSuccessHandler;  // 注销成功返回的 JSON 格式数据给前端(否则为 登录时的 html)

      @Autowired
      LoginAccessDeniedHandler loginAccessDeniedHandler;    // 无权访问返回的 JSON 格式数据给前端(否则为 403 html 页面)

      @Autowired
      LoginInvalidSessionStrategy loginInvalidSessionStrategy;


      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
          auth.authenticationProvider(mobileCodeAuthenticationProvider()).authenticationProvider(usernameAuthenticationProvider()).authenticationProvider(wxAuthenticationProvider());
      }
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          //这里是在校验密码之前先校验验证码,如果验证码错误就不检验用户名和密码了
          http.addFilterBefore(new LoginFilter(), UsernamePasswordAuthenticationFilter.class);
          http.addFilterBefore(mobileCodeAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
          http.addFilterBefore(usernameAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
          http.addFilterBefore(wxAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
          http.authorizeRequests()
                  .antMatchers("/**/index.html").permitAll()
                  .antMatchers("/login/**").permitAll()
                  .antMatchers("/mobileLogin/**").permitAll()
                  .antMatchers("/wxLogin/**").permitAll()
                  .anyRequest()
                  .permitAll()
                  .and().formLogin()
                  .permitAll()
                  .and()
                  .logout().logoutSuccessHandler(loginlogoutSuccessHandler).permitAll()
                  .and()
                  .exceptionHandling().authenticationEntryPoint(loginAuthenticationEntryPoint)
                  .and().csrf().disable()
                  .cors().disable();
    }
    /**
     * 跨域配置
     * @return 基于URL的跨域配置信息
     */
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        // 注册跨域配置
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Bean
    public MobileCodeAuthenticationProcessingFilter mobileCodeAuthenticationProcessingFilter() throws Exception {
        MobileCodeAuthenticationProcessingFilter filter = new MobileCodeAuthenticationProcessingFilter();
        filter.setAuthenticationManager(super.authenticationManagerBean());
        filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler());
        filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler());
        return filter;
    }
    @Bean
    public UsernameAuthenticationProcessingFilter usernameAuthenticationProcessingFilter() throws Exception {
        UsernameAuthenticationProcessingFilter filter = new UsernameAuthenticationProcessingFilter();
        filter.setAuthenticationManager(super.authenticationManagerBean());
        filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler());
        filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler());
        return filter;
    }
    @Bean
    public WxAuthenticationProcessingFilter wxAuthenticationProcessingFilter() throws Exception {
        WxAuthenticationProcessingFilter filter = new WxAuthenticationProcessingFilter();
        filter.setAuthenticationManager(super.authenticationManagerBean());
        filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler());
        filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler());
        return filter;
    }
    @Bean
    public MobileCodeAuthenticationProvider mobileCodeAuthenticationProvider() {
        return new MobileCodeAuthenticationProvider();
    }

    @Bean
    public UsernameAuthenticationProvider usernameAuthenticationProvider() {
        return new UsernameAuthenticationProvider();
    }

    @Bean
    public WxAuthenticationProvider wxAuthenticationProvider() {
        return new WxAuthenticationProvider();
    }
    @Bean
    public LoginAuthenticationFailureHandler myAuthenticationFailureHandler() {
        return new LoginAuthenticationFailureHandler();
    }

    @Bean
    public LoginAuthenticationSuccessHandler myAuthenticationSuccessHandler() {
        return new LoginAuthenticationSuccessHandler();
    }
}

可以实现AuthenticationFailureHandler重写onAuthenticationFailure来对登陆异常进行 统一的处理。可以实现AuthenticationSuccessHandler重写onAuthenticationSuccess对登陆成功进行统一处理

这样就完成了三种登陆方式了

部分概念及原理学习于https://blog.csdn.net/qq_36521507/article/details/103365805

  • 11
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值