Backend Development 17 min read

Integrating WeChat Web Authorization Login with Spring Security (Username + WeChat)

This article demonstrates how to integrate account username and WeChat web‑authorization login into a Spring Security application by configuring custom authentication providers, filters, tokens, and handlers, allowing users to log in without a password while leveraging WeChat OpenID verification.

Top Architect
Top Architect
Top Architect
Integrating WeChat Web Authorization Login with Spring Security (Username + WeChat)

Overview: This article explains how to integrate account username and WeChat web authorization login into a Spring Security based application, allowing login without password verification.

Preparation: It lists prerequisite articles on Spring Boot + Spring Security login and WeChat open platform third‑party login.

Project structure: (image omitted) shows the module layout.

Spring Security core configuration (WebSecurityConfig): The configuration defines two authentication methods—username/password and token based on WeChat OpenID—by registering custom authentication providers and filters, setting login pages, URLs, and security policies.

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired MyAuthenticationnSuccessHandler myAuthenticationSuccessHandler;
    @Autowired MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    @Autowired WxAuthenticationnSuccessHandler wxAuthenticationnSuccessHandler;
    @Autowired WxAuthenticationFailureHandler wxAuthenticationFailureHandler;
    @Autowired private DataSource dataSource;
    @Autowired RedisOneNetUtil redisOneNetUtil;
    @Value("${companyLog.loginPage}") private String loginPage;

    @Bean
    public JdbcTokenRepositoryImpl tokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        // tokenRepository.setCreateTableOnStartup(true); // startup create table, comment after success
        return tokenRepository;
    }

    @Bean
    UserDetailsService customUserService() {
        // register UserDetailsService bean
        return new CustomUserServiceImpl();
    }

    @Bean
    UserDetailsService weChatUserService() {
        // register UserDetailsService bean
        return new WeChatUserServiceImpl();
    }

    /**
     * Add authentication logic for both username/password and token login.
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        // username/password login
        auth.userDetailsService(customUserService()).passwordEncoder(new BCryptPasswordEncoder());
        // WeChat openid login
        auth.authenticationProvider(weChatAuthenticationProvider());
    }

    @Bean
    public WeChatAuthenticationProvider weChatAuthenticationProvider() {
        return new WeChatAuthenticationProvider();
    }

    @Bean
    public WeChatAuthenticationFilter weChatAuthenticationFilter() throws Exception {
        WeChatAuthenticationFilter filter = new WeChatAuthenticationFilter();
        filter.setAuthenticationManager(authenticationManagerBean());
        filter.setAuthenticationSuccessHandler(wxAuthenticationnSuccessHandler);
        filter.setAuthenticationFailureHandler(wxAuthenticationFailureHandler);
        return filter;
    }

    @Bean
    public CustomAuthenticationFilter customAuthenticationFilter() throws Exception {
        CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
        filter.setAuthenticationManager(authenticationManagerBean());
        filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
        filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);
        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        HttpMethodFilter filter = new HttpMethodFilter();
        WeChatAuthenticationFilter wechatFilter = weChatAuthenticationFilter();
        CustomAuthenticationFilter customFilter = customAuthenticationFilter();
        ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
        validateCodeFilter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);
        http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(wechatFilter, UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class)
            .addFilterAfter(validateCodeFilter, HttpMethodFilter.class)
            .formLogin()
            .loginPage(loginPage)
            .loginProcessingUrl("/user/login")
            .loginProcessingUrl("/wechat/weChatLogin")
            .and()
            .authorizeRequests()
            .antMatchers(loginPage, "/comMonAssessScreens", "/comMonAssessScreen", "/alarmConfiguration/ifCheck", "/logOut", "/code/image", "/meterData/insertElecMeterDataList", "/meterDataCreate*", "/common/**", "/common/js/**", "/wechat/login", "/wechat/weChatLogin", "/wechat/userLogin", "/wechat/userBindLogin", "/wechat/userBindGo", "/wechat/userBind", "/wechat/userUnBind", "/weChatLogin", "/weChatLogin.html", "/indexV2").permitAll()
            .antMatchers("/static/**").permitAll()
            .antMatchers("/views/**").permitAll()
            .antMatchers("/script/**").hasAuthority("ROLE_SuperPermission")
            .antMatchers("/**").fullyAuthenticated()
            .and()
            .logout()
            .logoutUrl("/logOut")
            .invalidateHttpSession(true)
            .and()
            .headers().frameOptions().sameOrigin().and()
            .rememberMe().tokenRepository(tokenRepository()).tokenValiditySeconds(3600).and()
            .csrf().disable()
            .headers()
            .contentSecurityPolicy("frame-ancestors 'self'; default-src 'self' 'unsafe-inline' 'unsafe-eval' *.aliyuncs.com *.baidu.com *.bdimg.com ;object-src 'self'");
    }
}

Custom tokens: Two token classes are defined—CustomAuthenticationToken for username/password and WeChatAuthenticationToken for WeChat OpenID.

public class CustomAuthenticationToken extends UsernamePasswordAuthenticationToken {
    private static final long serialVersionUID = -1076492615339314113L;
    public CustomAuthenticationToken(Object principal, Object credentials) {
        super(principal, credentials);
    }
    public CustomAuthenticationToken(Object principal, Object credentials, Collection
authorities) {
        super(principal, credentials, authorities);
    }
}
public class WeChatAuthenticationToken extends UsernamePasswordAuthenticationToken {
    private static final long serialVersionUID = -6231962326068951783L;
    public WeChatAuthenticationToken(Object principal) {
        super(principal, "");
    }
    public WeChatAuthenticationToken(Object principal, Collection
authorities) {
        super(principal, "", authorities);
    }
}

Custom filters: CustomAuthenticationFilter intercepts /user/login , extracts username and password, creates a CustomAuthenticationToken and delegates to the authentication manager. WeChatAuthenticationFilter intercepts /wechat/weChatLogin , extracts the openid, creates a WeChatAuthenticationToken and delegates.

public class CustomAuthenticationFilter 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 CustomAuthenticationFilter() {
        super("/user/login");
    }
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        String username = obtainUsername(request);
        String password = obtainPassword(request);
        if (username == null) username = "";
        if (password == null) password = "";
        username = username.trim();
        CustomAuthenticationToken authRequest = new CustomAuthenticationToken(username, password);
        setDetails(request, authRequest);
        return this.getAuthenticationManager().authenticate(authRequest);
    }
    protected String obtainPassword(HttpServletRequest request) {
        String password = request.getParameter(passwordParameter);
        return password == null ? "" : password;
    }
    protected String obtainUsername(HttpServletRequest request) {
        String username = request.getParameter(usernameParameter);
        return username == null ? "" : username;
    }
    protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }
}
public class WeChatAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    private String openidParameter = "openid";
    public WeChatAuthenticationFilter() {
        super("/wechat/weChatLogin");
    }
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (!request.getMethod().equals(HttpMethod.GET.name())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        String openid = obtainOpenid(request);
        if (openid == null || openid.length() == 0) {
            throw new BadCredentialsException("uid or openid is null.");
        }
        WeChatAuthenticationToken authRequest = new WeChatAuthenticationToken(openid);
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
        return this.getAuthenticationManager().authenticate(authRequest);
    }
    protected String obtainOpenid(HttpServletRequest request) {
        String openid = request.getParameter(this.openidParameter);
        return openid == null ? "" : openid.trim();
    }
}

Custom UserDetailsService: Loads user information and authorities from remote services, stores the username in the session, and returns a Spring Security User object.

@Service
public class CustomUserServiceImpl implements UserDetailsService {
    @Autowired UserControllerClient userControllerClient;
    @Override
    public UserDetails loadUserByUsername(String username) {
        SysUser user = userControllerClient.getUserInfoByLoginName(username);
        if (user != null) {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            HttpSession session = request.getSession();
            session.setAttribute("username", username);
            List
permissionCodess = userControllerClient.findPermissionByAdminUserName(username);
            List
grantedAuthorities = new ArrayList<>();
            for (String permissionCode : permissionCodess) {
                if (permissionCode != null && !permissionCode.isEmpty()) {
                    GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permissionCode);
                    grantedAuthorities.add(grantedAuthority);
                }
            }
            return new User(user.getUsername(), user.getPassword(), grantedAuthorities);
        } else {
            throw new UsernameNotFoundException("admin: " + username + " do not exist!");
        }
    }
}

Custom AuthenticationProvider: WeChatAuthenticationProvider validates the OpenID by querying the user‑WeChat mapping, loads the associated user and authorities, and returns an authenticated WeChatAuthenticationToken .

public class WeChatAuthenticationProvider implements AuthenticationProvider {
    @Autowired UserWeChatClient userWeChatClient;
    @Autowired UserControllerClient userControllerClient;
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        if (authentication.isAuthenticated()) {
            return authentication;
        }
        WeChatAuthenticationToken authenticationToken = (WeChatAuthenticationToken) authentication;
        String openid = (String) authenticationToken.getPrincipal();
        SysUser user = null;
        UserWeChatDto uwcDto = new UserWeChatDto();
        uwcDto.setOpenId(openid);
        List
uwcList = userWeChatClient.getListByParam(uwcDto);
        if (uwcList != null && uwcList.size() == 1) {
            UserWeChatDto userWeChatDto = uwcList.get(0);
            user = userControllerClient.getUserById(userWeChatDto.getUserId());
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            HttpSession session = request.getSession();
            session.setAttribute("username", user.getUsername());
        } else {
            throw new BadCredentialsException("微信授权openid无效,请重新登陆");
        }
        if (user == null) {
            throw new BadCredentialsException("微信授权openid无效,请重新登陆");
        }
        List
permissionCodess = userControllerClient.findPermissionByAdminUserName(user.getUsername());
        List
authorities = new ArrayList<>();
        for (String permissionCode : permissionCodess) {
            if (permissionCode != null && !permissionCode.isEmpty()) {
                GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permissionCode);
                authorities.add(grantedAuthority);
            }
        }
        WeChatAuthenticationToken authenticationResult = new WeChatAuthenticationToken(openid, authorities);
        return authenticationResult;
    }
    @Override
    public boolean supports(Class
authentication) {
        return WeChatAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

Success and failure handlers: WxAuthenticationnSuccessHandler redirects to /index.html on successful authentication, while WxAuthenticationFailureHandler returns a JSON response containing error details.

@Service
public class WxAuthenticationnSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.sendRedirect("/index.html");
    }
}
@Service
public class WxAuthenticationFailureHandler implements AuthenticationFailureHandler {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        Map result = new HashMap();
        result.put("wx_success", false);
        result.put("codeRtn", false);
        result.put("errorMsg", exception.getMessage());
        String json = objectMapper.writeValueAsString(result);
        response.setContentType("text/json;charset=utf-8");
        response.getWriter().write(json);
    }
}

Conclusion: By combining the preparation resources and the code provided above, developers can achieve username plus WeChat web‑authorization login integrated with Spring Security.

backendjavaauthenticationWeChat LoginSpring Security
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.