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

news2025/1/18 1:52:41

前言

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

小程序登录流程在这里插入图片描述

Spring Security中的OAuth 2.0 ​​ 授权码模式:
在这里插入图片描述
获取授权码code部分已经由小程序做过了, 现在我们无需再自己的服务oauth2去获取code,而是要直接去认证获取我们所需要的access_token 信息;

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


思路

在这里插入图片描述
小程序实现Filter 过滤器链来完成, 基于ProxyFilter代理
默认的过滤器顺序列表

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

实现

登录拦截器
@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<RequestMatcher> 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<String, Object> 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<CustomerAuthenticationProvider> authenticationProviderList;

    @Resource
    private CustomerAuthenticationSuccessHandler customerAuthenticationSuccessHandler;

    @Resource
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.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<String> 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<String> 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);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/10039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Intellij插件之~图形界面Swing UI Designer

资料 Java Swing 介绍 JavaFX快速入门 Java Swing 图形界面开发简介 GUI Designer Basics scrcpy ScrcpyController Services&#xfeff; 创建一个Gui Form文件(类form文件) 创建一个Gui Form 此时生成两个类, 是自动关联的 鼠标可以拖入控件,每拖入一个组件,在TestForm…

领悟《信号与系统》之 信号与系统的描述-下节

信号与系统的描述-下节一、信号的基本运算1. 信号的基本运算1. 加法 、减法2. 乘法、除法3. 微分 、差分4.积分、迭分2. 关于时间&#xff08;自变量&#xff09;的运算1. 位移2. 反折3. 尺度变换二、阶跃信号与冲激信号1. 单位阶跃信号2. 单位阶跃信号的特性3. 单位冲激信号4.…

Android架构师学习必备学习宝典《Android架构开发手册》

吐槽 我想每个程序员在写代码的时候可能都有这些历程(夸张)&#xff1a; 这坨代码谁写的&#xff0c;怎么要这样写啊&#xff0c;我这个需求该怎么加代码&#xff01;(尝试在shit山上小心地走&#xff0c;并添加新代码)写的好难受&#xff0c;shit越改越chou了…算了&#xf…

协程设计原理

文章目录1、协程的背景1.1、同步与异步1.2、为什么使用协程1.3、协程的适用场景2、协程的原语操作3、协程的切换3.1、汇编实现4、协程的定义4.1、多状态集合设计4.2、调度器的定义4.2、调度策略生产者消费者模式多状态运行5、api 封装5.1、hook 机制5.2、hook 函数原型5.3、hoo…

React笔记——github案例(用到axios 和 pubsub)

案例github用上脚手架配置代理 1.完成静态页面构建 小技巧&#xff1a;先在原html页面搜索最外侧框 是否有样式存在&#xff0c;如果样式不存在则不需要剪切过去 给需求或效果分好组件&#xff0c;分别是 Search 和 List 、App 组件 class都改为 className 给图片添加上特定…

JS高级(二):继承、数组的一些api、Object.defineProperty()、call、apply、bind

JavaScript高级&#xff08;二&#xff09;一、继承1.call方法改变this指向2.构造函数中模拟类的super实现属性继承3.构造函数借助原型对象实现方法继承4.类的本质二、ES5几个新增方法1.数组forEach()2.数组filter()3.数组some()4.字符串trim()三、Object.definProperty()四、改…

基于STM32结合CubeMX学习Free-RT-OS的源码之深入学习软件定时器实现过程

概述 关于在CUBEMX上的配置 介绍 软件定时器基于硬件定时器实现。 软件定时器允许设置一段时间&#xff0c;当设置的时间到达之后就执行指定的功能函数&#xff0c;被定时器 调用的这个功能函数叫做定时器的回调函数。回调函数的两次执行间隔叫做定时器的定时周期&#xff0c;…

什么是需求分析,如何进行需求分析?

目录 前言 需求分析在分析什么 如何看待产品原型设计 技术同学培养产品意识 如何应对需求变更问题 总结 重点&#xff1a;配套学习资料和视频教学 前言 这篇文章&#xff0c;我会将软件工程中关于需求分析相关的知识进行总结梳理&#xff0c;并以自己理解的方式进行阐述…

iNFTnews|风口之上,耐克推出的web3平台.SWOOSH能否引领市场?

本周一&#xff0c;著名的体育运动品牌耐克宣布&#xff0c;公司将进一步进军Web3&#xff0c;并将发布一个旨在通过旗下的数字可穿戴设备吸引用户的新平台——.SWOOSH。 耐克表示&#xff0c;.SWOOSH将成为Web3教育的资源库&#xff0c;以及购买和交易虚拟运动鞋或运动衫等数…

Oracle SQL执行计划操作(3)——物化视图相关操作

3. 物化视图相关操作 该类操作与SQL语句执行计划中访问物化视图数据的路径和方式相关,主要包括物化视图访问类相关操作。根据不同的具体SQL语句及其他相关因素,如下各操作可能会出现于相关SQL语句的执行计划。 1)MAT_VIEW ACCESS FULL 对物化视图(Materialized View)直…

培训学校的教务管理系统存在的问题有哪些?

教务管理在培训学校管理里面占据不可或缺的地位。随着计算机、网络、大数据、人工智能等技术的发展&#xff0c;国家对智慧校园的重视&#xff0c;促进了培训学校教务管理信息化与智慧化建设。然而&#xff0c;随着科技进步速度不断加快&#xff0c;教育改革步伐的不断加大&…

解决:将Ubuntu系统打包成ios镜像并制作U盘系统

将Ubuntu系统打包成ios镜像并制作U盘系统一、安装 Systemback二、将创建的.sblive镜像文件转为.iso格式三、写入U盘进行安装四、制作系统U盘一、安装 Systemback Currently supported Ubuntu releases: - 14.04.X LTS - 15.04 - 15.10 - 16.04.X LTS - 16.10Systemback的作者在…

linux的基本指令(中)

文章目录1.man指令1.安装2.用法3.man数字1. printf函数的查询2.cp指令1.cp 文件1.拷贝到当前目录2.拷贝到 其他目录中3. 拷贝到上一级目录2.cp 目录1.返回上一级目录3. mv指令1.剪切2. 文件的重命名4. cat指令1.显示文件的全部内容并且不可以修改2.cat -n指令3. cat -s 指令5. …

6张思维导图,搞定项目管理!(PMP项目管理可用)

工作中&#xff0c;我们最常遇到的就是大大小小的工作项目。项目要怎么做&#xff0c;才能100%达成目标呢&#xff1f; 小哈总结了6组项目管理思维导图。只要从五大阶段掌握诀窍&#xff0c;用项目管理的思维去管理工作&#xff0c;工作就能有条不紊按预期达到目标&#xff0c…

GitHub Codespaces 安装 .NET 7

本文主要介绍如何在 GitHub Codespaces 这个云上 IDE 环境中安装 .NET 7 背景 GitHub 的 Codespaces 可以让我们随时随地编写代码&#xff0c;一些简单的修改也非常方便快捷。特别是 .NET 7 发布后&#xff0c;一些可以直接升级的小项目只需要更改配置就可以了&#xff0c;我们…

EN 14915实木镶板和包层—CE认证

实木镶板和包层CE认证&#xff08;欧盟强制认证&#xff09;&#xff0d;简介 在欧盟市场“CE”标志属强制性认证标志&#xff0c;以表明产品符合欧盟《技术协调与标准化新方法》指令的基本要求。这是欧盟法律对产品提出的一种强制性要求。 在实木镶板和包层上加贴CE标志不但可…

Active Directory报表计划

ADManager Plus的“计划报表”功能是一个独有模块&#xff0c;可使报表生成实现自动化。IT管理员现在可为任何所需的时间段&#xff08;从一个小时到一个月&#xff09;计划报表。因而&#xff0c;计划功能可提供一致、准确的报表交付&#xff0c;而不会产生任何麻烦和费用。本…

【ESP32_8266_WiFi (十三)】ESP8266自动配网 – WiFiManager库使用说明

文章目录ESP8266自动配网 – WiFiManager库使用说明1 WiFiManager库使用说明1.1 WiFi配置流程1.2 WiFi配置示例程序1.2.1 预备程序 – 清理ESP8266储存的WiFi连接信息1.2.2 WiFiManager网络配置示例程序1.2.3 WiFiManager网络配置测试2 WiFiManager库汉化和定制说明2.1 WiFiMan…

Spring(十)- Spring Bean的基本注解

文章目录一、Spring Bean的基本注解一、Spring Bean的基本注解 Spring除了xml配置文件进行配置之外&#xff0c;还可以使用注解方式进行配置&#xff0c;注解方式慢慢成为xml配置的替代方案。我们有了xml开发的经验&#xff0c;学习注解开发就方便了许多&#xff0c;注解开发更…

调节自噬的小分子化合物

自噬? 生物体需要通过不断合成和降解物质来维持自身的内稳态&#xff08;Homeostasis&#xff09;。细胞内物质的降解主要通过两种途径进行&#xff1a;泛素化蛋白酶体途径&#xff08;Ubiquitin-proteasome system, UPS&#xff09;和自噬溶酶体途径&#xff08;Autophagy-ly…