Spring Security 自定义拦截器Filter实现登录认证

前言

需求来源: 微信小程序获取授权码code, 通过授权码code, 获取微信用户信息(比如openid,unionId), 并记录登录状态(比如token信息的获取);
原本打算使用Spring Security中OAuth2.0的机制 实现用小程序登录,发现小程序再已经获取授权码code登录流程和Spring Security中OAuth 2.0登录的流程有点不一样,所以直接使用spring security的Filter进行处理;

小程序登录流程Spring Security 自定义拦截器Filter实现登录认证_第1张图片

Spring Security中的OAuth 2.0 ​​ 授权码模式:
Spring Security 自定义拦截器Filter实现登录认证_第2张图片
获取授权码code部分已经由小程序做过了, 现在我们无需再自己的服务oauth2去获取code,而是要直接去认证获取我们所需要的access_token 信息;
Spring Security 自定义拦截器Filter实现登录认证_第3张图片

小程序已经持有了​​code​​​,它依然需要将​​code​​传递给后端服务器来执行后面的流程。那么我们能不能利用图2中第3个调用​​redirectUri​​​的步骤呢?换个角度来看问题第三方就是小程序反正它也是将一个​​code​​传递给了后端服务器,只要返回登录状态就行了,反正剩下的登录流程都跟小程序无关。我觉得它是可以的。在Spring Security中我们可以使用​​code​​​通过​​tokenUri​​​来换取​​token​​​。那么在微信小程序登录流程中,​​code​​​最终换取的只是登录态,没有特定的要求。但是后端肯定需要去获取用户的一些信息,比如​​openId​​​,用户微信信息之类的。总之要根据微信平台提供的API来实现。通过改造​​tokenUri​​​和​​userInfoUri​​可以做到这一点。


思路

Spring Security 自定义拦截器Filter实现登录认证_第4张图片
小程序实现Filter 过滤器链来完成, 基于ProxyFilter代理
默认的过滤器顺序列表

order 过滤器名称
100 ChannelProcessingFilter
200 ConcurrentSessionFilter
300 SecurityContextPersistenceFilter
400 LogoutFilter
500 X509AuthenticationFilter
600 RequestHeaderAuthenticationFilter
700 CasAuthenticationFilter
800 UsernamePasswordAuthenticationFilter
900 OpenIDAuthenticationFilter
1000 DefaultLoginPageGeneratingFilter
1100 DigestAuthenticationFilter
1200 BasicAuthenticationFilter
1300 RequestCacheAwareFilter
1400 SecurityContextHolderAwareRequestFilter
1500 RememberMeAuthenticationFilter
1600 AnonymousAuthenticationFilter
1700 SessionManagementFilter
1800 ExceptionTranslationFilter
1900 FilterSecurityInterceptor
2000 SwitchUserFilter

实现

登录拦截器
@Slf4j
public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    @Resource
    private SecurityConfigProperties securityConfigProperties;
    @Resource
    private JwtConfigProperties jwtConfigProperties;
    private Class requestDataType;

    public LoginAuthenticationFilter(AuthenticationManager authenticationManager,String loginPath) {
        super(new AntPathRequestMatcher(loginPath));
        super.setAuthenticationManager(authenticationManager);
    }

    @Override
    public void afterPropertiesSet() {
        Assert.notNull(securityConfigProperties.getRequestDataTypeName(), "登录请求数据类型必须被设定");
        try {
            this.requestDataType = Class.forName(securityConfigProperties.getRequestDataTypeName());
        } catch (ClassNotFoundException var2) {
            Assert.notNull(this.requestDataType, "登录请求数据类型必须是有效的类型");
        }
        super.afterPropertiesSet();
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        ServletInputStream inputStream = request.getInputStream();
        // String requestBody = StreamUtils.copyToString(inputStream, Charset.forName("UTF-8"));
        Object requestData = new ObjectMapper().readValue(inputStream, this.requestDataType);
        if (requestData != null) {
            if (requestData instanceof Map) {
                // 可以扩展不同的参数类型走不同的认证处理器; 比如走jwt的时候,会走JwtAuthenticationToken相关的认证处理器JwtAuthenticationProvider
            }
            // 此处不同引入的模块走自己的登录认证Provider
            Authentication auth = this.getAuthenticationManager().authenticate((Authentication)requestData);
            if (auth != null) {
                UserDetails userDetail = (UserDetails)auth.getDetails();
                request.setAttribute(jwtConfigProperties.getUserKey(), userDetail.getUsername());
                return auth;
            } else {
                return null;
            }
        } else {
            throw new RuntimeException("无授权用户信息");
        }
    }

    @Override
    public void destroy() {
        if (log.isInfoEnabled()) {
            log.info("正在注销......");
        }
    }

}
认证token拦截器
@Slf4j
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsService userService;
    @Resource
    private JwtConfigProperties jwtConfigProperties;
    @Resource
    private TokenParser tokenParser;
    private List permissiveRequestMatchers;
    @Autowired
    private JwtTokenService jwtTokenService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String requestURI = request.getRequestURI();
        if (log.isDebugEnabled()) {
            log.debug("开始对请求:{}进行认证", requestURI);
        }
        if (!this.requireAuthentication(request)) {
            filterChain.doFilter(request, response);
            return;
        }
        // 获取 认证头
        String authorizationHeader = request.getHeader(jwtConfigProperties.getAuthorizationHeaderName());
        if (!checkIsTokenAuthorizationHeader(authorizationHeader)) {
            log.debug("获取到认证头Authorization的值:[{}]但不是我们系统中登录后签发的。", authorizationHeader);
            filterChain.doFilter(request, response);
            return;
        }
        String token = JwtTokenOperator.getToken(request, jwtConfigProperties.getAuthorizationHeaderName(), jwtConfigProperties.getTokenHeaderPrefix());
        JwtAuthInfo authInfo = tokenParser.parse(token, jwtConfigProperties.getTokenType());
        if (authInfo == null) {
            writeJson(response, "认证token不合法");
            return;
        }
        if (authInfo.getRefreshToken()) {
            writeJson(response, "认证token不合法,请勿直接用刷新token认证");
            return;
        }
        String userKey = authInfo.getUserKey();
        UserDetails user = this.userService.loadUserByUsername(userKey);
        if (ObjectUtil.isEmpty(user)) {
            writeJson(response, "用户不存在,无效令牌");
            return;
        }
        if (authInfo.getExpirationTime() < System.currentTimeMillis()) {
            // 令牌失效自动刷新令牌
            handleTokenExpired(response, request);
        }
        // 构建认证对象
        JwtAuthenticationToken jwtAuthToken = new JwtAuthenticationToken(user, authInfo, user.getAuthorities());
        request.setAttribute(jwtConfigProperties.getSignatureKey(), userKey);
        jwtAuthToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(
                request));
        SecurityContextHolder.getContext().setAuthentication(jwtAuthToken);
        filterChain.doFilter(request, response);
    }

    /**
     * 請求認證
     * @param request
     * @return
     */
    private boolean requireAuthentication(HttpServletRequest request) {
        String authHeader = request.getHeader(jwtConfigProperties.getAuthorizationHeaderName());
        if  (authHeader == null) {
            if (log.isDebugEnabled()) {
                log.debug("请求头中不包含令牌信息,所以将跳过认证");
            }
            return false;
        }
        if (CollectionUtil.isNotEmpty(this.permissiveRequestMatchers)) {
            Iterator var2 = this.permissiveRequestMatchers.iterator();
            while(var2.hasNext()) {
                RequestMatcher matcher = (RequestMatcher)var2.next();
                boolean isPermissiveUrl = matcher.matches(request);
                if (isPermissiveUrl) {
                    if (log.isDebugEnabled()) {
                        log.debug("请求:{}为特权请求,将跳过认证", request.getRequestURI());
                    }
                    return false;
                }
            }
        }
        return true;
    }

    @Override
    protected void initFilterBean() throws ServletException {
        super.initFilterBean();
        if (CollectionUtil.isNotEmpty(jwtConfigProperties.getPermissiveRequestUrls())) {
            this.permissiveRequestMatchers = new ArrayList(jwtConfigProperties.getPermissiveRequestUrls().size());
            Iterator var1 = jwtConfigProperties.getPermissiveRequestUrls().iterator();

            while(var1.hasNext()) {
                String url = (String)var1.next();
                AntPathRequestMatcher matcher = new AntPathRequestMatcher(url);
                this.permissiveRequestMatchers.add(matcher);
            }
        }
    }

    @Override
    protected String getAlreadyFilteredAttributeName() {
        if (log.isDebugEnabled()) {
            log.debug("正在检查时否已经拦截过滤过");
        }
        String name = this.getClass().getName();
        return name + ".FILTERED";
    }

    /**
     * 判断是否是系统中登录后签发的token
     *
     * @param authorizationHeader
     * @return
     */
    private boolean checkIsTokenAuthorizationHeader(String authorizationHeader) {
        if (StringUtils.isBlank(authorizationHeader)) {
            return false;
        }
        if (!StringUtils.startsWith(authorizationHeader, jwtConfigProperties.getTokenHeaderPrefix())) {
            return false;
        }
        return true;
    }

    /**
     * 处理token过期情况
     *
     * @param response
     * @param request
     * @return
     * @throws IOException
     */
    private void handleTokenExpired(HttpServletResponse response, HttpServletRequest request) throws IOException, ServletException {
        // 获取刷新 token
        String refreshTokenHeader = request.getHeader(jwtConfigProperties.getRefreshHeaderName());
        // 检测 refresh-token 是否是我们系统中签发的
        if (!checkIsTokenAuthorizationHeader(refreshTokenHeader)) {
            log.debug("获取到刷新认证头:[{}]的值:[{}]但不是我们系统中登录后签发的。", jwtConfigProperties.getRefreshHeaderName(), refreshTokenHeader);
            writeJson(response, "token过期了,refresh token 不是我们系统签发的");
            return;
        }
        String referToken = JwtTokenOperator.getToken(request,jwtConfigProperties.getRefreshHeaderName(),jwtConfigProperties.getTokenHeaderPrefix());

        JwtAuthInfo authInfo = this.tokenParser.parse(referToken, jwtConfigProperties.getTokenType());
        if (authInfo == null) {
            writeJson(response, "refresh token不合法");
            return;
        }
        // 判断 refresh-token 是否过期
        if (authInfo.getExpirationTime() < System.currentTimeMillis()) {
            writeJson(response, "refresh token 过期了");
            return;
        }
        if (authInfo.getRefreshToken()) {
            writeJson(response, "refresh token不合法,请勿直接用认证token刷新令牌");
            return;
        }
        // 重新签发 token
        authInfo.setEffectiveTime(0L);
        String userToken = jwtTokenService.generateUserToken(authInfo);
        // 刷新 refresh token, 刷新token,提供刷新token接口获取
       // authInfo.setEffectiveTime(0L);
       // String refreshToken = jwtTokenService.generateRefreshUserToken(authInfo);
        response.addHeader(jwtConfigProperties.getAuthorizationHeaderName(), jwtConfigProperties.getTokenHeaderPrefix() + userToken);
       // response.addHeader(jwtConfigProperties.getRefreshHeaderName(), jwtConfigProperties.getTokenHeaderPrefix() + refreshToken);
    }

    private void writeJson(HttpServletResponse response, String msg) throws IOException {
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.getWriter().println(JSONUtil.parse(CommonResult.buildFailure(StatusEnum.UNAUTHORIZED, msg)));
    }
}
token 处理
@Service
public class JwtTokenService {
    @Resource
    private JwtConfigProperties jwtConfigProperties;

    private static String SECURITY_NAMESPACE_PREFIX = "security-auth";

    public String generateUserToken(JwtAuthInfo auth) {
        String token = this._generateUserToken(auth);
        return token;
    }

    public JwtAuthInfo parseToken(String token) {
        if (StringUtils.isNotBlank(jwtConfigProperties.getTokenHeaderPrefix()) && token.startsWith(jwtConfigProperties.getTokenHeaderPrefix())) {
            token = token.substring(jwtConfigProperties.getTokenHeaderPrefix().length());
        }
        return (JwtAuthInfo) TokenParserRegistrar.getInstance().getParser(jwtConfigProperties.getTokenType()).parse(token, jwtConfigProperties.getSignatureKey(), jwtConfigProperties.getTokenType());
    }

    public String generateRefreshUserToken(JwtAuthInfo auth) {
        long startTime = auth.getEffectiveTime();
        if (startTime <= 0L) {
            startTime = System.currentTimeMillis();
            auth.setEffectiveTime(startTime);
            auth.setIssueTime(startTime);
            long expireTime = startTime + jwtConfigProperties.getRefreshTokenExpiredSecond();
            auth.setExpirationTime(expireTime);
        }
        auth.setRefreshToken(true);
        return generateCommonToken(auth, jwtConfigProperties.getAlgorithmName(), jwtConfigProperties.getSignatureKey());
    }

    private String _generateUserToken(JwtAuthInfo auth) {
        long startTime = auth.getEffectiveTime();
        if (startTime <= 0L) {
            startTime = System.currentTimeMillis();
            auth.setEffectiveTime(startTime);
            auth.setIssueTime(startTime);
            long expireTime = startTime + jwtConfigProperties.getTokenExpireSecond();
            auth.setExpirationTime(expireTime);
        }
        auth.setRefreshToken(false);
        String token = generateCommonToken(auth, jwtConfigProperties.getAlgorithmName(), jwtConfigProperties.getSignatureKey());
        this.cacheToken(auth, token);
        return token;
    }

    private void cacheToken(JwtAuthInfo jwtAuthInfo,String token) {
        //String cacheKey = this.buildTokenCacheKey(userId, tokenId);
        //this.redisTemplate.opsForValue().set(cacheKey, token);
        //this.redisTemplate.expire(cacheKey, jwtConfigProperties.getRefreshInterval() + 5000L, TimeUnit.MILLISECONDS);
        RedisUtils.setObject(buildTokenCacheKey(jwtAuthInfo), token, Integer.parseInt(String.valueOf(jwtConfigProperties.getTokenExpireSecond())));

    }
    private String buildTokenCacheKey(JwtAuthInfo jwtAuthInfo) {
        return String.join(":",
                SECURITY_NAMESPACE_PREFIX,
                jwtAuthInfo.getApplicationKey(),
                jwtAuthInfo.getUserKey());
    }

    public String fetchToken(JwtAuthInfo jwtAuthInfo) {
        String cacheKey = this.buildTokenCacheKey(jwtAuthInfo);
        String cachedToken = RedisUtils.getObject(cacheKey, String.class);
        return cachedToken;
    }

    public String generateCommonToken(AuthInfo authInfo, String algorithm, String signatureKey) {
        JwtAuthInfo jwtAuthInfo = (JwtAuthInfo)authInfo;
        Map header = new HashMap();
        header.put("alg", jwtConfigProperties.getAlgorithmName());
        header.put("typ", "JWT");
        JwtBuilder builder = Jwts.builder().setHeader(header).setHeaderParam("refresh_token", authInfo.getRefreshToken()).setSubject(jwtAuthInfo.getApplicationKey()).setId(jwtAuthInfo.getUserKey()).setIssuer(jwtAuthInfo.getIssuer()).setIssuedAt(new Date(jwtAuthInfo.getIssueTime())).setExpiration(new Date(jwtAuthInfo.getExpirationTime())).setNotBefore(new Date(jwtAuthInfo.getEffectiveTime())).setAudience(jwtAuthInfo.getTokenUser());
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.forName(algorithm);
        builder.signWith(signatureAlgorithm, signatureKey);
        return builder.compact();
    }

}

配置信息
security
@ConditionalOnProperty(name="security.enable",havingValue="true")
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private SecurityConfigProperties securityConfigProperties;
    @Resource
    private JwtConfigProperties jwtConfigProperties;

    @Resource
    private UserDetailsService userDetailsService;
    // 处理业务的认证管理器
    @Resource
    private List authenticationProviderList;

    @Resource
    private CustomerAuthenticationSuccessHandler customerAuthenticationSuccessHandler;

    @Resource
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry registry = httpSecurity
                .authorizeRequests();
        for (String url : securityConfigProperties.getUrls()) {
            registry.antMatchers(url).permitAll();
        }
        //允许跨域请求的OPTIONS请求
        registry.antMatchers(HttpMethod.OPTIONS).permitAll();
        //任何请求需要身份认证
        registry.and()
                .authorizeRequests()
                .antMatchers("/login").permitAll()
                .antMatchers("/**/*.js").permitAll()
                .antMatchers("/**/*.css").permitAll()
                .antMatchers("/images/**").permitAll()
                .antMatchers("/**/*.html").permitAll()
                .antMatchers("/**/*.ftl").permitAll()
                .antMatchers(jwtConfigProperties.getRefreshTokenUrl()).permitAll()
                .anyRequest()
                // 允许认证过的用户访问
                .authenticated()
                // 关闭跨站请求防护及不使用session
                .and()
                .csrf()
                .disable()
                // //因为使用JWT,所以不需要HttpSession
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 自定义权限拒绝处理类
                .and()
                //允许配置错误处理
                .exceptionHandling()
                .accessDeniedHandler(restfulAccessDeniedHandler())
                .authenticationEntryPoint(restAuthenticationEntryPoint())
                // 自定义权限拦截器JWT过滤器
                .and()
                .addFilterAt(loginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)//登录Filter
                // 在指定的Filter类之前添加过滤器, 使用自定义的 Token过滤器 验证请求的Token是否合法
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 省份认证接口
     * @param auth 用来配置认证管理器AuthenticationManager
     *             装配自定义的Provider
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // jwt; 多个就配置多个
        for (CustomerAuthenticationProvider customerAuthenticationProvider : authenticationProviderList) {
            auth.authenticationProvider(customerAuthenticationProvider);
        }
        // 此处自定义userDetailsService;
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    /**
     * 强散列哈希加密实现
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public LoginAuthenticationFilter loginAuthenticationFilter() throws Exception{
        LoginAuthenticationFilter loginAuthenticationFilter = new LoginAuthenticationFilter(authenticationManagerBean(), securityConfigProperties.getLoginPath());
        // 自定义实现login success
        loginAuthenticationFilter.setAuthenticationSuccessHandler(customerAuthenticationSuccessHandler);
        return loginAuthenticationFilter;
    }



    @Bean
    public RestfulAccessDeniedHandler restfulAccessDeniedHandler() {
        return new RestfulAccessDeniedHandler();
    }

    @Bean
    public RestAuthenticationEntryPoint restAuthenticationEntryPoint() {
        return new RestAuthenticationEntryPoint();
    }

认证成功或失败村里
@Slf4j
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        log.info(request.getRequestURI() + authException.getMessage());
        response.getWriter().println(JSONUtil.parse(CommonResult.buildFailure(StatusEnum.UNAUTHORIZED)));
        response.getWriter().flush();
    }
}
@Slf4j
public class RestfulAccessDeniedHandler implements AccessDeniedHandler{
    @Override
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       AccessDeniedException e) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        log.info(request.getRequestURI() + e.getMessage());
        response.getWriter().println(JSONUtil.parse(CommonResult.buildFailure(StatusEnum.NO_OPERATION_PERMISSION)));
        response.getWriter().flush();
    }
}

jwt配置

@Component
@Data
public class JwtConfigProperties {
    @Value("${jwt.token-type:jwt}")
    private String tokenType;
    @Value("${jwt.authorization-header-name:Authorization}")
    private String authorizationHeaderName;
    // jwt 放开的请求
    @Value("#{'${jwt.permissive-request-urls:login}'.split(',')}")
    private List permissiveRequestUrls;

    @Value("${jwt.signature-algorithm:HS256}")
    private String algorithmName;

    @Value("${jwt.token-header-prefix:Bearer }")
    private String tokenHeaderPrefix = "Bearer ";

    @Value("${jwt.signature-key:xxxxx}")
    private String signatureKey;

    @Value("${jwt.token-expire-second:300000}")
    private Long tokenExpireSecond = 300000L;

    @Value("${jwt.refresh-token-url:/**/token/refresh}")
    private String refreshTokenUrl;

    @Value("${jwt.refresh-token-expired-second:400000}")
    private Long refreshTokenExpiredSecond= 86400000L;

    @Value("${jwt.refresh-header-name:Refresh-Token}")
    private String refreshHeaderName;

    @Value("${jwt.user-key:userKey}")
    private String userKey;
}

@Getter
@Setter
@Component
public class SecurityConfigProperties {
    @Value("#{'${security.url.ignored:login}'.split(',')}")
    private List urls = new ArrayList<>();
    @Value("${security.url.login.path:wx/login}")
    private String loginPath;
    @Value("${security.url.login.request-data-type}")
    private String requestDataTypeName;

}

#####设置认证类

@Getter
@Setter
public class DefaultMiniprogramAuthenticationData extends AbstractAuthenticationToken {
    private static final long serialVersionUID = 1L;
    /**小程序访问Code*/
    private String accessCode;;
    /**小程序会话key*/
    private String sessionKey;
    /**小程序openId*/
    private String openId;
    /**小程序unionId*/
    private String unionId;

    public DefaultMiniprogramAuthenticationData() {
        super(Collections.emptyList());
    }

    public DefaultMiniprogramAuthenticationData(MiniprogramUserDetail user, String sessionKey) {
        super(Collections.emptyList());
        super.setDetails(user);
        super.setAuthenticated(true);
        this.sessionKey = sessionKey;
    }

    @Override
    public Object getPrincipal() {
        return this.getDetails();
    }

    @Override
    public Object getCredentials() {
        return this.accessCode;
    }

}
@Component
@Slf4j
public class MiniprogramAuthenticationProvider implements CustomerAuthenticationProvider {
    @Autowired
    private ProgramWechatUserManager programWechatUserManager;
    @Autowired
    private MiniprogramAccountService miniprogramAccountService;

    @Autowired
    private ApplicationProperties applicationProperties;

    @Autowired
    private ProgramConfigProperties programConfigProperties;
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        log.info("MiniprogramAuthenticationProvider");
        if (!(authentication instanceof DefaultMiniprogramAuthenticationData)) {
            return null;
        }
        DefaultMiniprogramAuthenticationData authenticationToken = (DefaultMiniprogramAuthenticationData)authentication;
        String accessCode = authenticationToken.getAccessCode();
        try {
            UserinfoResponse userInfo = programWechatUserManager.getUserInfo(accessCode);
            if (userInfo == null) {
                if (log.isErrorEnabled()) {
                    log.error("使用访问令牌{}无法获取到用户信息", accessCode);
                }
                throw new BadCredentialsException("无法识别用户");
            } else {
                String sessionKey = userInfo.getSessionKey();
                String openId = userInfo.getOpenid();
                String unionId = userInfo.getUnionid();
             

                DefaultMiniprogramAuthenticationData authenticationProgramToken = new DefaultMiniprogramAuthenticationData(new MiniprogramUserDetail(miniprogramAccount), sessionKey);
                authenticationToken.setUnionId(unionId);
                authenticationToken.setOpenId(openId);
                return authenticationProgramToken;
            }
        } catch (Exception var10) {
            throw new RuntimeException(var10);
        }
    }

    @Override
    public boolean supports(Class authentication) {
        return authentication.isAssignableFrom(DefaultMiniprogramAuthenticationData.class);
    }
}

你可能感兴趣的:(java,spring,微信小程序,小程序,Spring,Security)