SpringBoot + Spring Security多种登录方式:账号+微信网页授权登录

一、概述

实现账号用户名+微信网页授权登录集成在Spring Security的思路,最重要的一点是要实现微信登录通过Spring Security安全框架时,不需要验证账号、密码。

二、准备工作

要实现该功能,首先需要掌握Spring Security框架和微信扫码登录接口相关技术,如果对这两块还不太熟悉,可以参考:

1、Springboot + Spring Security实现前后端分离登录认证及权限控制

  • https://blog.csdn.net/xue317378914/article/details/115318318

2、微信开放平台开发第三方授权登陆:微信扫码登录

  • https://blog.csdn.net/xue317378914/article/details/115318810

三、项目代码结构

89611c76aaeb7033ab13928919cbad6a.png

四、Spring Security核心配置:WebSecurityConfig

在WebSecurityConfig中配置了用户名密码登陆的验证以及token授权登陆两种方式,并分别通过不同的拦截器和不同的验证方式来实现该功能。

@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); // 启动创建表,创建成功后注释掉
    return tokenRepository;
  }
  @Bean
  UserDetailsService customUserService() { // 注册UserDetailsService 的bean
    return new CustomUserServiceImpl();
  }
  @Bean
  UserDetailsService weChatUserService() { // 注册UserDetailsService 的bean
    return new WeChatUserServiceImpl();
  }
  /**
   * 此处给AuthenticationManager添加登陆验证的逻辑。
   * 这里添加了两个AuthenticationProvider分别用于用户名密码登陆的验证以及token授权登陆两种方式。
   * 在处理登陆信息的过滤器执行的时候会调用这两个provider进行登陆验证。
   */
  @Override
  public void configure(AuthenticationManagerBuilder auth) throws Exception {
    //用户名和密码登陆
    auth.userDetailsService(customUserService()).passwordEncoder(new BCryptPasswordEncoder());
    //微信openid登陆
    auth.authenticationProvider(weChatAuthenticationProvider());
  }

  //用户名和密码登陆处理
  /*@Bean
  public CustomAuthenticationProvider customAuthenticationProvider() {
    return new CustomAuthenticationProvider();
  }
*/
  //微信openid登陆处理
  @Bean
  public WeChatAuthenticationProvider weChatAuthenticationProvider() {
    return new WeChatAuthenticationProvider();
  }

  /**
   * 添加微信openid登陆验证的过滤器
   */
  @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 {
    // http: // 192.168.1.225:8080/users/restPwdView?userid=6&taskcode=8grf3B
    HttpMethodFilter filter = new HttpMethodFilter();
    WeChatAuthenticationFilter wechatFilter = weChatAuthenticationFilter();
    CustomAuthenticationFilter customFilter = customAuthenticationFilter();
    ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
    validateCodeFilter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);
    // http.httpBasic()    //httpBasic登录 BasicAuthenticationFilter
    // 必须在注册之后的过滤器之间才能安插过滤器
    http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(wechatFilter, UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class)
        .addFilterAfter(validateCodeFilter, HttpMethodFilter.class)
        //表单登录,loginPage为登录请求的url,loginProcessingUrl为表单登录处理的URL
        .formLogin()
        .loginPage(loginPage)
        // 登录需要经过的url请求
        .loginProcessingUrl("/user/login")
        .loginProcessingUrl("/wechat/weChatLogin")
        //.successHandler(myAuthenticationSuccessHandler)
        //.failureHandler(myAuthenticationFailureHandler)
        .and()
        .authorizeRequests()
        .antMatchers(
            loginPage,
            "/comMonAssessScreens",
            "/comMonAssessScreen",
            "/alarmConfiguration/ifCheck",
            "/logOut",
            "/code/image",
            "/meterData/insertElecMeterDataList",
            "/meterDataCreate/*",
            "/common/**",
            "/common/js/**",
            
            "/wechat/login",
            "/wechat/weChatLogin_epf",
            "/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) // Token过期时间为一个小时
        .and()
        .csrf()
        .disable() // 注销行为任意访问
        .headers()
        // 增加csp防xss攻击    frame-ancestors 针对frame的加载策略     default-src 针对默认加载策略 object-src 针对插件的加载策略
        .contentSecurityPolicy(
            "frame-ancestors 'self'; default-src 'self' 'unsafe-inline' 'unsafe-eval' *.aliyuncs.com *.baidu.com *.bdimg.com ;object-src 'self'");
  }
}

1、configure分别配置两种登录验证方式,用户名和密码登陆使用userDetailsService方法返回的是带有用户名和密码的token,而authenticationProvider方法返回的是含有微信openid的自定义token,分别根据自己的验证逻辑来实现登录验证。

public void configure(AuthenticationManagerBuilder auth) throws Exception {
    //用户名和密码登陆
    auth.userDetailsService(customUserService()).passwordEncoder(new BCryptPasswordEncoder());
    //微信openid登陆
    auth.authenticationProvider(weChatAuthenticationProvider());
  }

2、分别定义两个拦截器,各自定义好需要拦截的登录url,并分别处理登录验证逻辑:

  • CustomAuthenticationFilter 拦截url: "/user/login"

  • WeChatAuthenticationFilter 拦截url:"/wechat/weChatLogin"

这两个url都在两个拦截器中有定义。

WeChatAuthenticationFilter wechatFilter = weChatAuthenticationFilter();
  CustomAuthenticationFilter customFilter = customAuthenticationFilter();
  ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
  validateCodeFilter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);
  // http.httpBasic()    //httpBasic登录 BasicAuthenticationFilter
  // 必须在注册之后的过滤器之间才能安插过滤器
  http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class)
          .addFilterBefore(wechatFilter, UsernamePasswordAuthenticationFilter.class)
          .addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class)
      .addFilterAfter(validateCodeFilter, HttpMethodFilter.class)
      //表单登录,loginPage为登录请求的url,loginProcessingUrl为表单登录处理的URL
      .formLogin()
      .loginPage(loginPage)
      // 登录需要经过的url请求
      .loginProcessingUrl("/user/login")
      .loginProcessingUrl("/wechat/weChatLogin")

3、两个拦截器分别实现了自己的登陆成功和失败的处理逻辑

/**
 * 添加微信openid登陆验证的过滤器
 */
@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;
}

五、自定义token

1、用户名和密码验证的token,需要账号密码作为验证

/**
 * @author: xxm
 * @description:用户名和密码验证的token
 */
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<? extends GrantedAuthority> authorities) {
        super(principal, credentials, authorities);
    }
}

2、微信验证的token,只需要一个openid作为验证即可

/**
 * @author: xxm
 * @description:微信验证的token`
 */
public class WeChatAuthenticationToken extends UsernamePasswordAuthenticationToken {

    private static final long serialVersionUID = -6231962326068951783L;


    public WeChatAuthenticationToken(Object principal) {
        super(principal, "");
    }


    public WeChatAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
        super(principal, "", authorities);
    }

}

六、自定义拦截器

1、用户名和密码登陆验证的过滤器,重写了拦截的请求URL,并定义好用户名、密码的参数名称,从请求中获取到用户名、密码,生成CustomAuthenticationToken

拦截器中生成的CustomAuthenticationToken,账号和密码是从前台传过来,它将会和UserDetailsService中返回的CustomAuthenticationToken的账号密码进行对比验证,账号密码是否正确。(UserDetailsService中返回的CustomAuthenticationToken的账号密码是从数据库查出来的)

/**
 * @author: xxm
 * @description:用户名和密码登陆验证的过滤器
 */
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() {
        //父类中定义了拦截的请求URL,/login的post请求,直接使用这个配置,也可以自己重写
        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);

        // Allow subclasses to set the "details" property
        setDetails(request,authRequest);

        return this.getAuthenticationManager().authenticate(authRequest);
    }

    protected String obtainPassword(HttpServletRequest request) {
        String password =request.getParameter(passwordParameter);
        return password == null ? "" : password;
    }

    /**
     * Enables subclasses to override the composition of the username, such as by
     * including additional values and a separator.
     *
     * @param request so that request attributes can be retrieved
     *
     * @return the username that will be presented in the <code>Authentication</code>
     * request token to the <code>AuthenticationManager</code>
     */
    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));
    }
}

2、微信openid登陆验证的过滤器,重写了拦截的请求URL,并定义好openid的参数名称,从请求中获取到openid,生成WeChatAuthenticationToken

拦截器中生成的WeChatAuthenticationToken,openid是从前台传过来,它将会传递给WeChatAuthenticationProvider,并在该类中验证微信授权openid是否有效(根据openid查询数据库中是否关联用户即可)。

/**
 * @author: xxm
 * @description:微信openid登陆验证的过滤器
 */
public class WeChatAuthenticationFilter extends AbstractAuthenticationProcessingFilter {


    private String openidParameter = "openid";



    public WeChatAuthenticationFilter() {
        super("/wechat/weChatLogin");
        //super.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());
    }

    /**
     * {@inheritDoc}
     */
    @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();
    }

}

七、自定义UserDetailsService

用户、密码登录采用了该种方式,从数据库查询出用户信息,并且查询出权限,返回带有权限的用户信息

/**
 * @author xxm
 * 定义UserDetailsService 接口
 */
@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<String> permissionCodess = userControllerClient.findPermissionByAdminUserName(username);
      List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
      for (String permissionCode : permissionCodess) {
        if (permissionCode != null && permissionCode != "") {
          GrantedAuthority grantedAuthority =
                  new SimpleGrantedAuthority(permissionCode);
          grantedAuthorities.add(grantedAuthority);
        }
      }
      // 返回带有权限的user
      return new User(user.getUsername(), user.getPassword(), grantedAuthorities);
    } else {
      throw new UsernameNotFoundException("admin: " + username + " do not exist!");
    }
  }
}

八、自定义Provider

微信登录采用了该种方式,根据WeChatAuthenticationFilter 传过来的token信息获取到openid,并根据openid查询微信关联账户,完成验证。

/**
 * @author: xxm
 * @description:
 * @date: 2021/3/11 16:07
 */
public class WeChatAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    UserWeChatClient userWeChatClient;
    @Autowired
    UserControllerClient userControllerClient;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        if (authentication.isAuthenticated()) {
            return authentication;
        }
        //获取过滤器封装的token信息
        WeChatAuthenticationToken authenticationToken = (WeChatAuthenticationToken) authentication;
        String openid = (String)authenticationToken.getPrincipal();
        SysUser user = null;
        UserWeChatDto uwcDto = new UserWeChatDto();
        uwcDto.setOpenId(openid);
        List<UserWeChatDto> uwcList = userWeChatClient.getListByParam(uwcDto);
        if (null != uwcList && uwcList.size()==1) {
            UserWeChatDto userWeChatDto = uwcList.get(0);
            //微信账号已经与网站账号关联
            //根据用户id查询用户
            user = userControllerClient.getUserById(userWeChatDto.getUserId());
            //存放session
            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<String> permissionCodess = userControllerClient.findPermissionByAdminUserName(user.getUsername());
        List<GrantedAuthority> authorities = new ArrayList<>();
        for (String permissionCode : permissionCodess) {
            if (permissionCode != null && permissionCode != "") {
                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);
    }

}

九、自定义Handler

根据验证成功与失败返回相应数据和操作

/**
 *
 * @author: xxm
 * 功能描述: 微信登陆成功后操作
 * @param: 
 * @return: 
 */
@Service
public class WxAuthenticationnSuccessHandler implements AuthenticationSuccessHandler {

  @Override
  public void onAuthenticationSuccess(
          HttpServletRequest request, HttpServletResponse response, Authentication authentication)
      throws IOException, ServletException {
    response.sendRedirect("/index.html");
  }
}
/**
*
* @author: xxm
* 功能描述: 微信登录验证失败操作
* @param: 
* @return: 
*/
@Service
public class WxAuthenticationFailureHandler implements AuthenticationFailureHandler {
private ObjectMapper objectMapper = new ObjectMapper();

@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
 // 返回json数据
 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);
}
}

结束

从准备工作的资料,加上本文的相关代码,就可以实现账号用户名+微信网页授权登录集成在Spring Security。

作者:小苹果1357

来源:blog.csdn.net/xue317378914/article/

details/115250414

推荐

Java面试题宝典

技术内卷群,一起来学习!!

36c641d9cd842c458eb9edc104cf17e4.jpeg

PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。点“在看”支持我们吧!

  • 1
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
该小程序源码项目是个人高分毕业设计项目源码,已获导师指导认可通过,都经过严格调试,确保可以运行!放心下载使用。 基于微信小程序的新闻资讯系统是一个为用户提供各类新闻资讯的平台,利用Spring Boot框架构建了后端服务,实现了以下主要功能: 微信小程序端: 用户可以使用微信账号登录或注册,完善个人信息。 提供新闻资讯的浏览功能,包括国内外新闻、财经、科技、娱乐等各类资讯。 实现新闻搜索和分类浏览功能,用户可以根据关键词或分类快速找到感兴趣的新闻。 提供新闻详情查看功能,用户可以查看新闻的详细内容、评论和相关推荐。 后端Spring Boot框架: 使用Spring Boot快速搭建后端服务,简化了项目配置和部署过程,提高了开发效率。 设计合理的RESTful API接口,实现前后端数据的交互和通信。 整合Spring Security实现用户认证和授权功能,确保用户信息的安全性。 利用Spring Data JPA进行数据库操作,包括新闻信息的存储和检索。 新闻管理与推荐系统: 管理员可以发布、编辑、删除新闻资讯,保持新闻内容的及时更新。 基于用户的浏览历史和兴趣偏好,实现个性化的新闻推荐功能,提高用户的浏览体验。 用户交互与社交功能: 用户可以对新闻进行评论和点赞,增强用户之间的交流和互动。 提供用户收藏和分享功能,方便用户保存喜欢的新闻并与好友分享。 性能优化与扩展性设计: 通过缓存技术提高系统性能,减少对数据库的频繁访问。 设计可扩展的系统架构,支持后续功能的拓展和升级,如新增新闻分类、推送功能等。 通过以上实现,基于微信小程序的新闻资讯系统为用户提供了一个便捷、多样化的新闻阅读平台,同时采用Spring Boot框架构建的后端服务保证了系统的稳定性和可扩展性,为用户提供了安全可靠的新闻资讯服务。
该小程序源码项目是个人高分毕业设计项目源码,已获导师指导认可通过,都经过严格调试,确保可以运行!放心下载使用。 基于H5的移动网赚项目是一个为用户提供在线任务赚钱的平台,利用Spring Boot框架构建了后端服务,实现了以下主要功能: H5移动网页端: 用户可以在手机浏览器中访问网站,无需下载App即可参与任务赚钱。 提供注册和登录功能,用户可以使用手机号码或第三方账号快速注册并登录。 展示各种任务类型,包括问卷调查、试玩游戏、看视频、下载App等,用户可以根据自己的兴趣和能力选择适合的任务。 实现任务完成记录和积分管理,用户完成任务后获得相应的积分奖励,可以用于兑换现金或实物奖励。 支持用户个人中心,用户可以查看账户余额、任务完成情况、积分明细等信息,管理自己的网赚活动。 后端Spring Boot框架: 使用Spring Boot快速搭建后端服务,提供稳定高效的接口响应。 设计合理的RESTful API接口,实现前后端数据交互和业务逻辑处理。 使用Spring Security等安全框架实现用户身份认证和权限管理,保障用户数据的安全性和隐私保护。 使用Spring Data JPA等持久化框架操作数据库,包括用户信息、任务信息、积分记录等,确保数据的完整性和一致性。 实现定时任务功能,包括任务状态更新、积分结算等,保证系统的稳定运行和任务的及时处理。 任务管理与推荐系统: 管理员可以发布各种类型的任务,并设置相应的奖励积分和完成条件。 基于用户的历史行为和兴趣偏好,实现个性化的任务推荐功能,提高用户的参与度和完成率。 用户交互与社交功能: 用户可以在完成任务后进行评论和分享,与其他用户进行互动和交流,增强用户的参与感和满足感。 提供邀请好友赚取积分的功能,鼓励用户通过分享和邀请扩大平台的用户群体。 性能优化与扩展性设计: 通过缓存技术提高系统性能,减少对数据库的频繁访问。 设计可扩展的系统架构,支持后续功能的拓展和升级,如新增任务类型、优化任务推荐算法等功能。 通过以上实现,基于H5的移动网赚项目为用户提供了一个灵活方便的赚钱平台,同时采用Spring Boot框架构建的后端服务保证了系统的稳定性和可扩展性,为用户提供了安全可靠的网赚活动服务。
【资源说明】 基于 SpringBoot+Vue核酸检测登记查询系统源码+数据库sql+项目说明.zip 该项目是个人毕设项目源码,评审分达到95分,都经过严格调试,确保可以运行!放心下载使用。 该项目资源主要针对计算机、自动化等相关专业的学生或从业者下载使用,也可作为期末课程设计、课程大作业、毕业设计等。 具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现类似其他功能。 核酸检测登记查询系统 natweb目录为前端项目 采用Vue+ElementUI+VantUI natserver目录为后端项目 采用SpringBoot+SpringSecurity+Mybatis+MySQL nat.sql 为数据库文件,nat_with_v2_system为兼容微信登录和非微信登陆的数据库 (admin默认密码为123456) (提醒:部署在服务器上时,请配置SSL证书,前端通过浏览器调用摄像头时必须为https协议) ## 项目配置 运行前请修改配置 前端配置路径 public/config.js 项目功能简介 ### 用户端 (路径:/#/user) 个人信息登记、个人信息二维码展示、检测结果查询 目前可以支持不使用微信平台来进行用户数据录入功能,添加了一套独立的用户登录功能(开关位于`UserLoginConfig.useWechet`),请使用nat.sql数据库文件来兼容独立用户登录功能和硬件节点信息功能 ### 采集端 (路径:/#/operator) 通过扫描试管条码和个人信息二维码进行信息录入 chrome 在47后调用navigator.mediaDevices.getUserMedia 仅能在在https和 loaclhost环境下才可以使用。本机调试的话**只有用户在浏览器端设置信任该域名才可以使用本地摄像头。** #### 设置方法 地址栏输入`chrome://flags/`, 搜索`unsafely` enabled 并填入要授信的域名。 ### 后台 (路径:/#/admin) 后台有两种角色可登录,超级管理员和采集单位账号 超级管理员可进行检测结果查询、人员信息查询、以及所有单位的试管管理、任务管理和采集人员管理 单位账号可进行本单位下的试管管理、任务管理和采集人员管理

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值