ruoyi-vue v3.8.3新增微信用户code登录(带用户权限)

1.创建微信登录token验证-WxCodeAuthenticationToken

模仿
UsernamePasswordAuthenticationToken 实现

package com.szbt.framework.security.wx;  
  
import org.springframework.security.authentication.AbstractAuthenticationToken;  
import org.springframework.security.core.GrantedAuthority;  
import org.springframework.security.core.SpringSecurityCoreVersion;  
  
import java.util.Collection;  
  
/**  
 * @author wut  
 * @PackageName:com.szbt.framework.security.authentication  
 * @ClassName:WxCodeAuthenticationToken  
 * @Description: 自定义微信登录token验证  
 * @date 2023/6/12 10:40  
 */
 public class WxCodeAuthenticationToken extends AbstractAuthenticationToken {  
  
    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;  
  
    /**  
     * 在 UsernamePasswordAuthenticationToken 中该字段代表登录的用户名,  
     * 在这里就代表登录的openId  
     */    private final Object principal;  
  
    /**  
     * 构建一个没有鉴权的 WxCodeAuthenticationToken  
     */    public WxCodeAuthenticationToken(Object principal) {  
        super(null);  
        this.principal = principal;  
        setAuthenticated(false);  
    }  
  
    /**  
     * 构建拥有鉴权的 WxCodeAuthenticationToken  
     */    
     public WxCodeAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {  
        super(authorities);  
        this.principal = principal;  
        // must use super, as we override  
        super.setAuthenticated(true);  
    }  
  
    @Override  
    public Object getCredentials() {  
        return null;  
    }  
  
    @Override  
    public Object getPrincipal() {  
        return this.principal;  
    }  
  
    @Override  
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {  
        if (isAuthenticated) {  
            throw new IllegalArgumentException(  
                    "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");  
        }  
  
        super.setAuthenticated(false);  
    }  
  
    @Override  
    public void eraseCredentials() {  
        super.eraseCredentials();  
    }  
  
}

2.创建登陆鉴权 Provider-WxCodeAuthenticationProvider

package com.szbt.framework.security.wx;  
  
import org.springframework.security.authentication.AuthenticationProvider;  
import org.springframework.security.core.Authentication;  
import org.springframework.security.core.AuthenticationException;  
import org.springframework.security.core.userdetails.UserDetails;  
import org.springframework.security.core.userdetails.UserDetailsService;  
  
/**  
 * @author wut  
 * @PackageName:com.szbt.framework.security.wx  
 * @ClassName:WxCodeAuthenticationProvider  
 * @Description: wx登陆鉴权 Provider,要求实现 AuthenticationProvider 接口  
 * @date 2023/6/12 10:47  
 */
 public class WxCodeAuthenticationProvider implements AuthenticationProvider {  
  
    private UserDetailsService userDetailsService;  
  
    @Override  
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {  
        WxCodeAuthenticationToken authenticationToken = (WxCodeAuthenticationToken) authentication;  
  
        String openId = (String) authenticationToken.getPrincipal();  
  
        UserDetails userDetails = userDetailsService.loadUserByUsername(openId);  
  
        // 此时鉴权成功后,应当重新 new 一个拥有鉴权的 authenticationResult 返回  
        WxCodeAuthenticationToken authenticationResult = new WxCodeAuthenticationToken(userDetails, userDetails.getAuthorities());  
  
        authenticationResult.setDetails(authenticationToken.getDetails());  
  
        return authenticationResult;  
    }  
  
  
    @Override  
    public boolean supports(Class<?> authentication) {  
        // 判断 authentication 是不是 WxCodeAuthenticationToken 的子类或子接口  
        return WxCodeAuthenticationToken.class.isAssignableFrom(authentication);  
    }  
  
    public UserDetailsService getUserDetailsService() {  
        return userDetailsService;  
    }  
  
    public void setUserDetailsService(UserDetailsService userDetailsService) {  
        this.userDetailsService = userDetailsService;  
    }  
}

3.编写UserDetailsService实现类-UserDetailsByOpenIdServiceImpl

package com.szbt.framework.web.service;  
  
import com.szbt.common.core.domain.entity.SysUser;  
import com.szbt.common.core.domain.model.LoginUser;  
import com.szbt.common.enums.UserStatus;  
import com.szbt.common.exception.base.BaseException;  
import com.szbt.common.utils.StringUtils;  
import com.szbt.system.service.ISysUserService;  
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;  
  
/**  
 * @author wut  
 * @PackageName:com.szbt.framework.web.service  
 * @ClassName:UserDetailsByOpenIdServiceImpl  
 * @Description:  wx用户验证处理  
 * @date 2023/6/12 10:48  
 */
@Service("UserDetailsByOpenIdServiceImpl")  
public class UserDetailsByOpenIdServiceImpl implements UserDetailsService {  
  
    private static final Logger log = LoggerFactory.getLogger(UserDetailsByOpenIdServiceImpl.class);  
  
    @Autowired  
    private ISysUserService userService;  
  
    @Autowired  
    private SysPermissionService permissionService;  
  
    @Override  
    public UserDetails loadUserByUsername(String openId) throws UsernameNotFoundException {  
        SysUser user = userService.selectWxUserByOpenId(openId);  
        if (StringUtils.isNull(user)) {  
            log.info("登录用户:{} 不存在.", openId);  
            throw new UsernameNotFoundException("登录用户:" + openId + " 不存在");  
        } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {  
            log.info("登录用户:{} 已被删除.", openId);  
            throw new BaseException("对不起,您的账号:" + openId + " 已被删除");  
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {  
            log.info("登录用户:{} 已被停用.", openId);  
            throw new BaseException("对不起,您的账号:" + openId + " 已停用");  
        }  
  
        return createLoginUser(user);  
    }  
  
    public UserDetails createLoginUser(SysUser user) {  
        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));  
    }  
}

4. 完善SecurityConfig配置类

package com.szbt.framework.config;  
  
import com.szbt.framework.security.filter.JwtAuthenticationTokenFilter;  
import com.szbt.framework.security.handle.AuthenticationEntryPointImpl;  
import com.szbt.framework.security.handle.LogoutSuccessHandlerImpl;  
import com.szbt.framework.security.wx.WxCodeAuthenticationProvider;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.beans.factory.annotation.Qualifier;  
import org.springframework.context.annotation.Bean;  
import org.springframework.http.HttpMethod;  
import org.springframework.security.authentication.AuthenticationManager;  
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;  
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;  
import org.springframework.security.config.annotation.web.builders.HttpSecurity;  
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;  
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;  
import org.springframework.security.config.http.SessionCreationPolicy;  
import org.springframework.security.core.userdetails.UserDetailsService;  
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;  
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;  
import org.springframework.security.web.authentication.logout.LogoutFilter;  
import org.springframework.web.filter.CorsFilter;  
import com.szbt.framework.config.properties.PermitAllUrlProperties;  
  
/**  
 * spring security配置  
 *  
 * @author szbt  
 */
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)  
public class SecurityConfig extends WebSecurityConfigurerAdapter {  
    /**  
     * 自定义用户认证逻辑  
     */  
    @Autowired  
    @Qualifier("UserDetailsByUsernameServiceImpl")  
    private UserDetailsService userDetailsService;  
  
  
    /**  
     * 自定义用户(手机号验证码)认证逻辑  
     */  
    @Autowired  
    @Qualifier("UserDetailsByOpenIdServiceImpl")  
    private UserDetailsService userDetailsServiceByOpenId;  
  
    /**  
     * 认证失败处理类  
     */  
    @Autowired  
    private AuthenticationEntryPointImpl unauthorizedHandler;  
  
    /**  
     * 退出处理类  
     */  
    @Autowired  
    private LogoutSuccessHandlerImpl logoutSuccessHandler;  
  
    /**  
     * token认证过滤器  
     */  
    @Autowired  
    private JwtAuthenticationTokenFilter authenticationTokenFilter;  
  
    /**  
     * 跨域过滤器  
     */  
    @Autowired  
    private CorsFilter corsFilter;  
  
    /**  
     * 允许匿名访问的地址  
     */  
    @Autowired  
    private PermitAllUrlProperties permitAllUrl;  
  
    /**  
     * 解决 无法直接注入 AuthenticationManager  
     *     * @return  
     * @throws Exception  
     */    
    @Bean  
    @Override    
    public AuthenticationManager authenticationManagerBean() throws Exception {  
        return super.authenticationManagerBean();  
    }  
  
    /**  
     * 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 {  
  		
  		// wx登陆鉴权 Provider
        WxCodeAuthenticationProvider wxCodeAuthenticationProvider = new WxCodeAuthenticationProvider();  
        wxCodeAuthenticationProvider.setUserDetailsService(userDetailsServiceByOpenId);  
  
        // 注解标记允许匿名访问的url  
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();  
        permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());  
  
        httpSecurity  
                // CSRF禁用,因为不使用session  
                .csrf().disable()  
                // 禁用HTTP响应标头  
                .headers().cacheControl().disable().and()  
                // 认证失败处理类  
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()  
                // 基于token,所以不需要session  
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()  
                // 过滤请求  
                .authorizeRequests()  
                // 对于登录login 注册register 验证码captchaImage 允许匿名访问  
                .antMatchers("/login", "/register", "/captchaImage").permitAll()  
                // 对于登录wxlogin  允许匿名访问  
                .antMatchers("/wxLogin").permitAll()  
                // 静态资源,可匿名访问  
                .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()  
                .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid-5694/**").permitAll()  
                // 除上面外的所有请求全部需要鉴权认证  
                .anyRequest().authenticated()  
                .and()  
                .headers().frameOptions().disable();  
        // 添加Logout filter  
        httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);  
        // 添加JWT filter  
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);  
        // 添加CORS filter  
        httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);  
        httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class)  
                //wx登录验证的provider  
                .authenticationProvider(wxCodeAuthenticationProvider);;  
    }  
  
    /**  
     * 强散列哈希加密实现  
     */  
    @Bean  
    public BCryptPasswordEncoder bCryptPasswordEncoder() {  
        return new BCryptPasswordEncoder();  
    }  
  
    /**  
     * 身份认证接口  
     */  
    @Override  
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {  
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());  
    }  
}

5.编写wxCode登录接口

5.1 SysLoginController中添加登录接口

/**  
 * 登录方法  
 *  
 * @param wxLoginBody 登录信息  
 * @return 结果  
 */  
@PostMapping("/wxLogin")  
public AjaxResult wxLogin(@RequestBody WxLoginBody wxLoginBody) {  
    AjaxResult ajax = AjaxResult.success();  
    //微信官方提供的微信小程序登录授权时使用的URL地址  
    String url = "https://api.weixin.qq.com/sns/jscode2session";  
  
    /**  
     * 拼接需要的参数  
     * appid = AppID 你自己的微信小程序APPID  
     * js_code = AppSecret 你自己的微信APP密钥  
     * grant_type=authorization_code = code 微信官方提供的临时凭证  
     */  
    String params = StrUtil.format("appid={}&secret={}&js_code={}&grant_type=authorization_code", wxAppConfig.getAppId(), wxAppConfig.getAppSecret(), wxLoginBody.getCode());  
    //向微信服务器发送恳求获取用户信息  
	String res = HttpUtils.sendGet(url, params);  
	log.info("wxLogin返回:{}", res);  
	WxLoginResultVo wxLoginResultVo = JSON.parseObject(res, WxLoginResultVo.class);  
	if (wxLoginResultVo.getErrcode() == 40029) {  
		return AjaxResult.error("wxLoginCode无效");  
	}  
	if (wxLoginResultVo.getErrcode() == 45011) {  
		return AjaxResult.error("API 调用太频繁,请稍候再试");  
	}  
	if (wxLoginResultVo.getErrcode() == 40226) {  
		return AjaxResult.error("高风险等级用户,小程序登录拦截 。");  
	}  
	if (wxLoginResultVo.getErrcode() == -1) {  
		return AjaxResult.error("系统繁忙,此时请开发者稍候再试");  
	}  
	String openid = wxLoginResultVo.getOpenid();  
	if (StrUtil.isEmpty(openid)) {  
		return AjaxResult.error("未获取到openid");  
    }  
    // 生成令牌  
    String token = loginService.wxLogin(openid, wxLoginBody.getNickName(), wxLoginBody.getAvatarUrl());  
    ajax.put(Constants.TOKEN, token);  
    return ajax;  
}

5.2 SysLoginService中添加登录服务

/**  
 * 微信登录  
 *  
 * @param openId 登录凭据 只能用一次  
 * @return  
 */  
public String wxLogin(String openId, String nickName, String avatarUrl) {  
  
    // 微信用户首次登录创建用户  
    //依据openid判别数据库中是否有该用户  
    //依据openid查询用户信息  
    SysUser wxUser = userService.selectWxUserByOpenId(openId);  
    //假如查不到,则新增,查到了,则更新  
    String nickNameStr = StringUtils.isEmpty(nickName) ? getStringRandom(8) : nickName;  
    String avatarUrlStr = StringUtils.isEmpty(avatarUrl) ? "/profile/avatar/2023/05/30/blob_20230530184944A001.png" : avatarUrl;  
    SysUser user = new SysUser();  
    if (ObjectUtil.isEmpty(wxUser)) {  
        // 新增  
        log.info("微信用户不存在,注册中...");  
        user.setUserName("wx" + getStringRandom(14));// 生成16位随机用户名  
        user.setPassword(SecurityUtils.encryptPassword("wx20230606@"));  
        user.setNickName(nickNameStr);  
        user.setAvatar(avatarUrlStr);  
        user.setOpenId(openId);  
        user.setDeptId(100L);  
        user.setCreateBy("微信注册");  
        //新增 用户  
        userService.insertUser(user);  
        // 分配角色  可根据需求设置默认角色及权限
        userService.insertUserAuth(user.getUserId(), new Long[]{100L});  
        // 操作完成后 查询用户明细信息  
    } else {  
        //更新  
        user = wxUser;  
        user.setNickName(nickNameStr);  
        user.setAvatar(avatarUrlStr);  
        user.setUpdateTime(DateUtils.getNowDate());  
        userService.updateUserProfile(user);  
    }  
  
    // 用户验证  
    Authentication authentication = null;  
    try {  
        // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername  
        authentication = authenticationManager  
                .authenticate(new WxCodeAuthenticationToken(openId));  
    } catch (Exception e) {  
        if (e instanceof BadCredentialsException) {  
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(openId, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));  
            throw new UserPasswordNotMatchException();  
        } else {  
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(openId, Constants.LOGIN_FAIL, e.getMessage()));  
            throw new MpsException(e.getMessage());  
        }  
    }  
    AsyncManager.me().execute(AsyncFactory.recordLogininfor(openId, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));  
    LoginUser loginUser = (LoginUser) authentication.getPrincipal();  
    // 生成token  
    return tokenService.createToken(loginUser);  
}  
  
//生成随机用户名,数字和字母组成,  
public static String getStringRandom(int length) {  
    String val = "";  
    Random random = new Random();  
    //参数length,表明生成几位随机数  
    for (int i = 0; i < length; i++) {  
        String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";  
        //输出字母仍是数字  
        if ("char".equalsIgnoreCase(charOrNum)) {  
            //输出是大写字母仍是小写字母  
            int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;  
            val += (char) (random.nextInt(26) + temp);  
        } else if ("num".equalsIgnoreCase(charOrNum)) {  
            val += String.valueOf(random.nextInt(10));  
        }  
    }  
    return "wx" + val;  
}

5.3 完善登录对象 微信用户登录对象

package com.szbt.common.core.domain.model;  
  
/**  
 * @author wut  
 * @PackageName:com.szbt.common.core.domain.model  
 * @ClassName:WxLoginBody  
 * @Description: 微信用户登录对象  
 * @date 2023/5/31 18:22  
 */public class WxLoginBody {  
  
    /**  
     * 暂时登陆凭据 code 只能运用一次  
     */  
    private String code;  
  
    /**  
     * 昵称  
     */  
    private String nickName;  
    /**  
     * 头像  
     */  
    private String avatarUrl;  
  
  
    public String getCode() {  
        return code;  
    }  
  
    public void setCode(String code) {  
        this.code = code;  
    }  
  
    public String getNickName() {  
        return nickName;  
    }  
  
    public void setNickName(String nickName) {  
        this.nickName = nickName;  
    }  
  
    public String getAvatarUrl() {  
        return avatarUrl;  
    }  
  
    public void setAvatarUrl(String avatarUrl) {  
        this.avatarUrl = avatarUrl;  
    }  
}

5.4 完善微信服务请求返回对象

package com.szbt.wxmpsms.domain.vo;  
  
  
/**  
 * @author wut  
 * @PackageName:com.szbt.wxmpsms.domain.vo  
 * @ClassName:WxLoginResultVo  
 * @Description: 微信服务请求返回对象  
 * @date 2023/5/31 12:18  
 */public class WxLoginResultVo {  
  
    /**  
     * 会话密钥  
     **/  
    private String session_key;  
  
    /**  
     * 用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台帐号下会返回  
     **/  
    private String unionid;  
  
    /**  
     * 错误信息  
     **/  
    private String errmsg;  
  
    /**  
     * 用户唯一标识 目前只用到这个返回数据  
     **/  
    private String openid;  
  
    /**  
     * 错误码  
     **/  
    private int errcode;  
  
    public String getSession_key() {  
        return session_key;  
    }  
  
    public void setSession_key(String session_key) {  
        this.session_key = session_key;  
    }  
  
    public String getUnionid() {  
        return unionid;  
    }  
  
    public void setUnionid(String unionid) {  
        this.unionid = unionid;  
    }  
  
    public String getErrmsg() {  
        return errmsg;  
    }  
  
    public void setErrmsg(String errmsg) {  
        this.errmsg = errmsg;  
    }  
  
    public String getOpenid() {  
        return openid;  
    }  
  
    public void setOpenid(String openid) {  
        this.openid = openid;  
    }  
  
    public int getErrcode() {  
        return errcode;  
    }  
  
    public void setErrcode(int errcode) {  
        this.errcode = errcode;  
    }  
}

6.还需调整的内容

6.1 原UserDetailsServiceImpl调整(必须调整)

@Service("UserDetailsByUsernameServiceImpl")
public class UserDetailsServiceImpl implements UserDetailsService {
	...
}

6.2 sysUser调整(必须调整)

  • sys_user 增加open_id字段
  • sysUser 增加openId字段
  • ISysUserService 增加selectWxUserByOpenId查询方法
  • ISysUserService 注意crud把openId字段补充哦!

6.3 MpsException为业务模块异常通知(按需增加)

我新增业务就是wxmps
在这里插入图片描述
具体代码为:

package com.szbt.common.exception.wxmpsms;

/**
 * @author wut
 * @PackageName:com.szbt.common.exception.wxmpsms
 * @ClassName:MpsException
 * @Description: mps服务异常
 * @date 2023/6/8 19:18
 */
public class MpsException extends RuntimeException {
    private static final long serialVersionUID = 1L;

    /**
     * 错误码
     */
    private Integer code;

    /**
     * 错误提示
     */
    private String message;

    /**
     * 错误明细,内部调试错误
     * <p>
     * 和 {@link CommonResult#getDetailMessage()} 一致的设计
     */
    private String detailMessage;

    /**
     * 空构造方法,避免反序列化问题
     */
    public MpsException() {
    }

    public MpsException(String message) {
        this.message = message;
    }

    public MpsException(String message, Integer code) {
        this.message = message;
        this.code = code;
    }

    public String getDetailMessage() {
        return detailMessage;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public Integer getCode() {
        return code;
    }

    public MpsException setMessage(String message) {
        this.message = message;
        return this;
    }

    public MpsException setDetailMessage(String detailMessage) {
        this.detailMessage = detailMessage;
        return this;
    }
}

6.4 WxAppConfig为微信小程序配置(按需增加,也可以直接在SysLoginController.wxLogin写死参数)

/**
 * @author toolman
 * @PackageName:com.szbt.common.config
 * @ClassName:WxAppConfig
 * @Description: 微信小程序配置
 * @date 2023/5/31 18:32
 */
@Component
@ConfigurationProperties(prefix = "wx-app")
public class WxAppConfig {

    /**
     * APPID
     */
    private String appId;

    /**
     * APP密钥
     */
    private String appSecret;

    public String getAppId() {
        return appId;
    }

    public void setAppId(String appId) {
        this.appId = appId;
    }

    public String getAppSecret() {
        return appSecret;
    }

    public void setAppSecret(String appSecret) {
        this.appSecret = appSecret;
    }
}

配置文件application.yml中添加

# 微信小程序配置
wx-app:
    appId: 你的appId
    appSecret: 你的appSecret

6.5 优化登录用户属性(按需参考,该方法为5.2中 SysLoginService.wxLogin)

  • 优化了昵称和用户名为上一个用户的id+1,
  • 部门和角色通过系统配置的字典获取
  • 启用userType字段做两种用户区分
 /**
     * 微信登录
     *
     * @param openId 登录凭据 只能用一次
     * @return
     */
    public String wxLogin(String openId, String nickName, String avatarUrl) {

        // 微信用户首次登录创建用户
        // 依据openid判别数据库中是否有该用户
        // 依据openid查询用户信息
        SysUser wxUser = userService.selectWxUserByOpenId(openId);
        // 假如查不到,则新增,查到了,则更新
        String nickNameStr = StringUtils.isEmpty(nickName) ? getWxGenUsername() : nickName;
        String avatarUrlStr = StringUtils.isEmpty(avatarUrl) ? "http://aa.jpg" : avatarUrl;
        SysUser user = new SysUser();
        if (ObjectUtil.isEmpty(wxUser)) {
            // 新增
            log.info("微信用户不存在,注册中...");
            user.setUserName(getWxGenUsername()); // 生成随机用户名,数字和字母组成
            user.setPassword(SecurityUtils.encryptPassword("wx20230606@"));
            user.setNickName(nickNameStr);
            user.setAvatar(avatarUrlStr);
            user.setOpenId(openId);
            // 00为系统用户 01为小程序用户
            user.setUserType("01");
            // 字典中添加默认用户部门
            user.setDeptId(Long.valueOf(configService.selectConfigByKey("hd.wxuser.dept")));
            user.setCreateBy("微信注册");
            // 新增 用户
            userService.insertUser(user);
            // 分配角色  可根据需求设置默认角色及权限
            // 获取默认角色
            String roleKey = configService.selectConfigByKey("hd.wxuser.role");
            SysRole defaultRole = roleService.selectRoleByKey(roleKey);
            userService.insertUserAuth(user.getUserId(), new Long[]{defaultRole.getRoleId()});
            // 操作完成后 查询用户明细信息
        } else {
            // 更新
            log.info("微信用户存在,登录中...");
            user = wxUser;
            if (StringUtils.isEmpty(wxUser.getAvatar())) {
                 user.setAvatar(avatarUrlStr);
            }
            if (StringUtils.isEmpty(wxUser.getAvatar())) {
                user.setNickName(nickNameStr);
             }
            user.setUpdateTime(DateUtils.getNowDate());
            userService.updateUserProfile(user);
        }
        // 用户验证
        Authentication authentication = null;
        try {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager
                    .authenticate(new WxCodeAuthenticationToken(openId));
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(openId, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            } else {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(openId, Constants.LOGIN_FAIL, e.getMessage()));
                throw new HdException(e.getMessage());
            }
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(openId, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        // 生成token
        return tokenService.createToken(loginUser);
    }

    // 生成随机用户名,数字和字母组成
    public String getWxGenUsername() {
        Long userId = userService.selectUserByLast() + 1;
        return "wx" + userId;
    }

7.测试登录效果

登录接口
在这里插入图片描述
权限接口:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值