微信小程序登录


在这里我没有获取小程序的登陆接口,直接是根据账号密码进行登录的

在这里插入图片描述
直接套上wxml ,样式就不详细介绍了


<!--pages/login/login.wxml-->
<cu-custom bgColor="bg-gradual-blue" >
    <view slot="content">登录</view>
</cu-custom>
<!--设置了动态的高度,这个高度是进来的时候适配-->
<view class="padding flex flex-direction justify-center" style="{{windowHeight}}">
  <view  style="font-size:36rpx; margin:30rpx 0;   font-weight: 800;"> 账号密码登录</view>
  <view  class="cu-aform-group" style=" margin-bottom: 30rpx;">
  	<!--给账号绑定事件,要用户名的改变而改变账号信息-->
    <input class="margin-tb-sm" type="text" placeholder="请输入账号" bindinput="bindKeyUsername"/>
  </view>
  <view  class="cu-form-group"  style=" margin-bottom: 30rpx;"> 
    	<!--bindinput	给密码绑定事件,要密码的改变而改变密码信息-->
      <input  class="margin-tb-sm" type="password" placeholder="请输入密码" bindinput="bindKeyPassword"/> 
  </view>
  <view class="cu-form-group">
		<view class="title">验证码</view>
		<input placeholder="输入验证码"  type="text" bindinput="bindKeyCaptcha"></input>
		<image class="bg-green shadow" bindtap="getCaptchaImage" style="height: 60rpx;  width: 200rpx;" src="{{captchaImage}}" />
	</view>
  <view class="flex" style="margin-top:30rpx;">
  	<!--向后台发起请求	bindtap="login"-->
    <button class="cu-btn bg-blue lg " style="width:100%" bindtap="login">登录</button>
  </view>
  <view class="flex"  style="color:#c4c4c4; font-size:28rpx;margin-top:30rpx;" bindtap="toRegister"> 
    注册
  </view>
</view>

这个是js,导入了一个api.js 这是一个自己封装的请求js. 获取的请求参数位置放在了app.js里面,设置一个全局的请求路径. 说一下啊图片验证码,验证码是通过base64a返回到前端的,小程序显示base64的话

			<image class="bg-green shadow" bindtap="getCaptchaImage" style="height: 60rpx;  width: 200rpx;" src="data:image/png;base64,base64字符" />
var api = require('../api/api.js')
const app = getApp()
Page({

  /**
   * 页面的初始数据
   */
  data: {
    captchaImage : undefined,
    uuid : undefined,
    username : undefined,
    password : undefined,
    captcha : undefined,
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    let that = this ;
    that.getCaptchaImage();
 },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  },
  bindKeyUsername:function(e){
    this.setData({
      username: e.detail.value
    })
  },
  bindKeyPassword : function(e){
    this.setData({
      password : e.detail.value
    })
  },
  bindKeyCaptcha:function(e){
    this.setData({
      captcha : e.detail.value
    })
  },
  login :function(){
    let that = this;
    wx.request({
      url:`${app.globalData.host}`+'/wechatLogin',
      method:'post',
      data:{
        username: that.data.username,
        password : that.data.password,
        uuid : that.data.uuid,
        code : that.data.captcha,
      },
      success(request) {
        if (request.data.code === 200) {
          // 成功了就直接进入到了index 页面
          wx.navigateTo({
            url: '/pages/index/index',
          })
          // 登录的token ,
          wx.setStorageSync('token',request.data.token);
        } else {
       wx.showToast({
         title: request.data.msg,
       })
          that.getCaptchaImage();
        }
      },
      fail(error) {
        reject(error.data)
      }
    })
  },
  getCaptchaImage :function(){
    let that = this ;
    api.notGet("/captchaImage").then(res=>{
      that.setData({
        uuid: res.uuid,
        captchaImage: "data:image/png;base64,"+res.img //结果图片
      })
    }).catch(err=>{
      console.log(err);
  })
  } 
})
const app = getApp()

const request = (url, options) => {
  return new Promise((resolve, reject) => {
    wx.request({
      url: `${app.globalData.host}${url}`,
      method: options.method,
      data: options.method === 'GET' ? options.data : JSON.stringify(options.data),
      header: {
        'Content-Type': 'application/json; charset=UTF-8',
        'Authorization': wx.getStorageSync('token')  // 看自己是否需要
      },
      success(request) {
        if (request.data.code === 200) {
          resolve(request.data)
        } else {
          reject(request.data)
        }
      },
      fail(error) {
        reject(error.data)
      }
    })
  })
}
const request1 = (url, options) => {
  return new Promise((resolve, reject) => {
    wx.request({
      url: `${app.globalData.host}${url}`,
      method: options.method,
      data: options.method === 'GET' ? options.data : JSON.stringify(options.data),
      header: {
        'Content-Type': 'application/json; charset=UTF-8',
      },
      success(request) {
        if (request.data.code === 200) {
          resolve(request.data)
        } else {
          reject(request.data)
        }
      },
      fail(error) {
        reject(error.data)
      }
    })
  })
}

const uploadFileRequest = (url,data)=>{
  return new Promise((resolve, reject) => {
  wx.uploadFile({
    filePath: data,
    name: 'file',
    url: `${app.globalData.host}`+ url,
    header: {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': wx.getStorageSync('token')  // 看自己是否需要
    },
    success:function(request){
      let data = JSON.parse(request.data)
      if (data.code === 200) {
        resolve(data)
      } else {
        reject(data)
      }
    },
    fail : function(err){
        reject(request.data)
       }
     })
    })
  }


const get = (url, options = {}) => {
  return request(url, { method: 'GET', data: options })
}

const uploadFile = (url, options = {}) => {
  return uploadFileRequest(url, options)
}
const notGet = (url, options = {}) => {
  return request1(url, { method: 'GET', data: options })
}

const post = (url, options) => {
  return request(url, { method: 'POST', data: options })
}

const put = (url, options) => {
  return request(url, { method: 'PUT', data: options })
}

// 不能声明DELETE(关键字)
const remove = (url, options) => {
  return request(url, { method: 'DELETE', data: options })
}

module.exports = {
  get,
  post,
  put,
  remove,
  notGet,
  uploadFile
}
后台代码

后台是springboot + security +jwt +redis实现的
===>先看数据库表结构、用户表的一些字段。

DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `dept_id` bigint(20) DEFAULT NULL COMMENT '部门ID',
  `user_name` varchar(30) NOT NULL COMMENT '用户账号',
  `nick_name` varchar(30) NOT NULL COMMENT '用户昵称',
  `user_type` varchar(2) DEFAULT '00' COMMENT '用户类型(00系统用户)',
  `email` varchar(50) DEFAULT '' COMMENT '用户邮箱',
  `phonenumber` varchar(11) DEFAULT '' COMMENT '手机号码',
  `sex` char(1) DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)',
  `avatar` varchar(100) DEFAULT '' COMMENT '头像地址',
  `password` varchar(100) DEFAULT '' COMMENT '密码',
  `status` char(1) DEFAULT '0' COMMENT '帐号状态(0正常 1停用)',
  `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
  `login_ip` varchar(128) DEFAULT '' COMMENT '最后登录IP',
  `login_date` datetime DEFAULT NULL COMMENT '最后登录时间',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';

在这里插入图片描述
后台代码集成的是若依框架,里面有具体的文档描述,不过我这个是前后分离版本。使用的是SpringSecurity 做为权限认证框架 。
通过springboot @Configuration 整合spring Security 添加对应的依赖框架。

        <!-- spring security 安全认证 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
package com.iot.mqtt.config;

import com.iot.mqtt.config.handler.AuthenticationEntryPointImpl;
import com.iot.mqtt.config.handler.LogoutSuccessHandlerImpl;
import com.iot.mqtt.config.service.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * TODO
 *
 * @author AZHE_SUN
 * @date 2021-7-8 15:16
 **/
@Configuration
@EnableWebSecurity
public class SecurityConfig  extends WebSecurityConfigurerAdapter {

    /**
     * 自定义用户认证逻辑
     */
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 认证失败处理类
     */
    @Autowired
    private AuthenticationEntryPointImpl unauthorizedHandler;

    /**
     * 退出处理类
     */
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;

    /**
     * token认证过滤器
     */
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;

    /**
     * 请求配置
     * anyRequest          |   匹配所有请求路径
     * access              |   SpringEl表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyAll             |   用户不能访问
     * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
     * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
     * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
     * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
     * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
     * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
     * permitAll           |   用户可以任意访问
     * rememberMe          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception
    {
        httpSecurity
                // CRSF禁用,因为不使用session
                .csrf().disable()
                // 认证失败处理类
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                // 基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 过滤请求
                .authorizeRequests()
                // 对于登录login 验证码captchaImage 允许匿名访问
                .antMatchers("/login", "/captchaImage","/deviceServer/*","/websocket/notice").anonymous()
                .antMatchers("/system/user/exportSellPlan").anonymous()
                .antMatchers(
                        HttpMethod.GET,
                        "/*.html",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js"
                ).permitAll()
//                .antMatchers("/minio/*").anonymous()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and()
                .headers().frameOptions().disable();
        httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
        // 添加JWT filter
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }
    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder()
    {
        return new BCryptPasswordEncoder();
    }

    /**
     * 身份认证接口
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception
    {

//通过构建者模式调用userDetailsService 使用接口用来作为登录的实现方法
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }
}

用户的登录信息时候进行校验认知的实现类在configure 进行了配置。

package com.sub.framework.security.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.sub.common.enums.UserStatus;
import com.sub.common.exception.BaseException;
import com.sub.common.utils.StringUtils;
import com.sub.framework.security.LoginUser;
import com.sub.project.system.domain.SysUser;
import com.sub.project.system.service.ISysUserService;

/**
 * 用户验证处理
 *
 * @author sub
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService
{
    private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);

    @Autowired
    private ISysUserService userService;

    @Autowired
    private SysPermissionService permissionService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
    {
        SysUser user = userService.selectUserByUserName(username);
        if (StringUtils.isNull(user))
        {
            log.info("登录用户:{} 不存在.", username);
            throw new UsernameNotFoundException("登录用户:" + username + " 不存在");
        }
        else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
        {
            log.info("登录用户:{} 已被删除.", username);
            throw new BaseException("对不起,您的账号:" + username + " 已被删除");
        }
        else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
        {
            log.info("登录用户:{} 已被停用.", username);
            throw new BaseException("对不起,您的账号:" + username + " 已停用");
        }

        return createLoginUser(user);
    }

    public UserDetails createLoginUser(SysUser user)
    {
        return new LoginUser(user, permissionService.getMenuPermission(user));
    }
}

LoginServiceImpl

用户登录的具体实现接口 // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(username, password));


    /**
     * 登录验证
     * 
     * @param username 用户名
     * @param password 密码
     * @param code 验证码
     * @param uuid 唯一标识
     * @return 结果
     */
    public String login(String username, String password, String code, String uuid)
    {
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
        String captcha = redisCache.getCacheObject(verifyKey);
        redisCache.deleteObject(verifyKey);
        if (captcha == null)
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha))
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
            throw new CaptchaException();
        }
        // 用户验证
        Authentication authentication = null;
        try
        {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
        }
        catch (Exception e)
        {
            if (e instanceof BadCredentialsException)
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            }
            else
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new CustomException(e.getMessage());
            }
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        // 生成token
        return tokenService.createToken(loginUser);
    }

用户登录控制层



   @Autowired
    private SysLoginService loginService;
    /**
     * 登录方法
     * 
     * @param username 用户名
     * @param password 密码
     * @param code 验证码
     * @param uuid 唯一标识
     * @return 结果
     */
    @PostMapping("/login")
    public AjaxResult login( LoginRequest loginRequest)
    {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.login(loginRequest.getUsername(), loginRequest.getPassword(), loginRequest.getCode(), loginRequest.getUuid());
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }

登录的控制层和实现层我没有具体叙述了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值