公司的业务需求,对接了微信公众号授权,通过微信公众号的接口拿到用户信息进行业务系统的登录,话不多说上代码,我的实现方式是整合了spingSecurity

首先是接口

    @PostMapping("/official/login")
@ApiOperation(value = "公众号授权登录", notes = "此接口返回系统的token")
public AjaxResult officialLogin(@RequestBody String code){
AjaxResult ajax = AjaxResult.success();
String token = mobileLoginService.officialLogin(code);
ajax.put(Constants.TOKEN, token);
return ajax;
}

然后是service

/**
* 公众号登录
* @param code 授权码
* @return token
*/
public String officialLogin(String code) {
// 用户验证
Authentication authentication = null;
try {
MobileUserByOfficialAuthenticationToken officialAuthenticationToken =
new MobileUserByOfficialAuthenticationToken(code);
AuthenticationContextHolder.setContext(officialAuthenticationToken);
// 该方法会去调用MobileUserByOfficialDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager.authenticate(officialAuthenticationToken);
} catch (Exception e) {
if (e instanceof BadCredentialsException) {
throw new UserPasswordNotMatchException();
} else {
throw new ServiceException(e.getMessage());
}
} finally {
AuthenticationContextHolder.clearContext();
}
MobileLoginUser mobileLoginUser = (MobileLoginUser) authentication.getPrincipal();
recordLoginInfo(mobileLoginUser.getUserId());
return tokenService.createToken(mobileLoginUser);
}

这里开始涉及到spring security,自定义一个MobileUserByOfficialAuthenticationToken ,用于authenticationManager找到合适的authenticationProvider来处理请求

/**
* @Description : 移动用户-公众号登录
* @Author : wzkris
* @Version : V1.0.0
* @Date : 2022/12/14 17:30
*/
public class MobileUserByOfficialAuthenticationToken extends AbstractAuthenticationToken { private final String code; /**
* Creates a token with the supplied array of authorities.
*/
public MobileUserByOfficialAuthenticationToken(String code) {
super(null);
this.code = code;
} /**
* @return 公众号授权需要的code
*/
public String getCode() {
return code;
} @Override
public Object getCredentials() {
return null;
} @Override
public Object getPrincipal() {
return null;
}
}
/**
* @Description : 公众号登录验证器
* @Author : wzkris
* @Version : V1.0.0
* @Date : 2022/12/14 17:33
*/
@Component
public class MobileUserByOfficialAuthenticationProvider implements AuthenticationProvider { @Resource(name = "mobileUserByOfficialDetailsServiceImpl")
private UserDetailsService userDetailsService; @Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
MobileUserByOfficialAuthenticationToken authenticationToken = (MobileUserByOfficialAuthenticationToken) authentication;
UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationToken.getCode());
//微信授权登录,无密码
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
} @Override
public boolean supports(Class<?> authentication) {
return MobileUserByOfficialAuthenticationToken.class.equals(authentication);
}
}

下面的是具体请求微信拿到openId的方法

/**
* @Description : 微信公众号登录服务
* @Author : wzkris
* @Version : V1.0.0
* @Date : 2022/12/14 17:35
*/
@Service
public class MobileUserByOfficialDetailsServiceImpl implements UserDetailsService { @Resource
private RestTemplate restTemplate; @Resource
private MobileUserWechatService mobileUserWechatService; @Resource
private MobileUserService mobileUserService; @Resource
private ISysConfigService configService; @Resource
private WxOfficialService wxOfficialService; @Resource
private TransactionTemplate transactionTemplate; @Override
public UserDetails loadUserByUsername(String code) throws UsernameNotFoundException {
//获取请求token
OfficialAccessResult loginAccessToken = wxOfficialService.getLoginAccessToken(code);
//构造请求
String url = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=" + loginAccessToken.getAccessToken()
+ "&openid=" + loginAccessToken.getOpenId()
+ "&lang=zh_CN";
ResponseEntity<OfficialLoginResult> response = restTemplate.getForEntity(URI.create(url), OfficialLoginResult.class);
OfficialLoginResult loginResult = response.getBody();
//校验返回结果
Objects.requireNonNull(loginResult);
WxErrCodeUtils.checkResult(loginResult);
//业务逻辑
MobileUserWechat userWechat = mobileUserWechatService.queryByOpenId(loginResult.getOpenId());
//不为空则代表已经注册过,直接查询出来返回
if (ObjectUtils.isNotEmpty(userWechat)) {
MobileUser user = mobileUserService.getById(userWechat.getUserId());
return createLoginUser(user);
}
//否则就代表第一次登录,直接插入并且注册
String password = configService.selectConfigByKey("sys.user.initPassword"); MobileUser user = new MobileUser()
.setPassword(SecurityUtils.encryptPassword(password))
.setUsername(IdUtils.fastSimpleUUID())
.setNickname(loginResult.getNickname())
.setAvatar(loginResult.getHeadImgUrl())
.setSex(exchangeSex(loginResult.getSex()))
.setPhone(Constants.UNKNOWN);
//开启事务,保存用户和微信信息
transactionTemplate.execute(status -> {
mobileUserService.save(user);
mobileUserWechatService.save(new MobileUserWechat()
.setOpenId(loginAccessToken.getOpenId())
.setUnionId(loginAccessToken.getUnionId())
.setChannel(Constants.CHANNEL_OFFICIAL)
.setUserId(user.getId()));
return null;
});
return createLoginUser(user);
} private UserDetails createLoginUser(MobileUser user) {
return new MobileLoginUser(user, Constants.CHANNEL_OFFICIAL);
} /**
* @param sex 性别
* @return 微信性别转换成系统的性别
*/
private int exchangeSex(int sex) {
int real = sex - 1;
if (real < 0) {
return 2;
}
return real;
} }

微信公众号授权登录,整合spring security的更多相关文章

  1. 【tp5.1】微信公众号授权登录及获取信息录入数据库

    微信公众号开发文档链接:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432 微信公众号授权登录分为两种: 1.以 ...

  2. 解决微信公众号授权登录和开放平台微信第三方应用授权登录获取到的用户Openid关联问题

    开发背景: 最近一段时间一直在做关于微信方面的网站应用开发,这段时间也收获的不少关于微信开发方面的开发技能,接触的比较多的主要有微信公众号和微信网站app第三方登录授权,以及微信会员卡,优惠券和扫描二 ...

  3. uniapp - 微信公众号授权登录

    [缘由] 采用uniapp进行微信小程序和微信公众号双版本开发:考虑到用户唯一性,我们后端确定了以“unionid”.作为唯一标识. 有的小伙伴估计也是刚入这坑,我就简单说一下步骤流程   [摸索] ...

  4. 微信公众号授权登录,提示“redirect_uri 参数错误”

    做微信公众号开发授权登录的时候遇到的坑... 后台服务用node,index.js相关代码如下: const oauth = new OAuth(conf.appid, conf.appsecret) ...

  5. 微信公众号授权登录后报redirect_uri参数错误的问题

      在进行微信公众号二次开发的时候,需要通过授权码模式来进行微信授权.比如,在进行登录的时候,用户点击了登录按钮,然后弹出一个授权框,用户点击同意后,就可以获取用户的OpenId等信息了.这篇文章主要 ...

  6. Chrome插件:微信公众号自动登录(chrome.extension)

    manifest.json: { "manifest_version": 2, "name": "WX.AutoLogin", " ...

  7. 微信公众号授权,支付,退款总结【shoucang】

    1.支付前准备 1.1首先两个平台接入账户. 商户平台:https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F 公众平台: ...

  8. PHP之路——微信公众号授权获取用户信息

    官方文档链接:http://mp.weixin.qq.com/wiki/4/9ac2e7b1f1d22e9e57260f6553822520.html /** * 获取code */ public f ...

  9. 微信公众号授权回调用户信息,获取openid

    1.--------------------用户授权登录并获取code 授权登录方式有两个,一种为静默授权登录(scope=snsapi_base),一种为非静默授权登录(scope=snsapi_u ...

  10. ASP.NET之MVC 微信公众号授权给第三方平台的技术实现流程(获取第三方平台access_token)

    “出于安全考虑,在第三方平台创建审核通过后,微信服务器每隔10分钟会向第三方的消息接收地址推送一次component_verify_ticket,用于获取第三方平台接口调用凭据”.这是文档中的原话,也 ...

随机推荐

  1. 做文件上传功能时,dubbo对MultipartFile文件传输时,一个bug:Fail to decode request due to: RpcInvocation

    三月 22, 2019 2:37:27 下午 org.apache.catalina.core.StandardWrapperValve invoke 严重: Servlet.service() fo ...

  2. unity笔记001

    熟悉场景和物体的基本操作,q移动场景,e旋转物体,放大缩小,V键顶点吸附,相比快捷键,还是喜欢用xyz参数控制

  3. HTML学习笔记4----更多元素

    随笔记录方便自己和同路人查阅. #------------------------------------------------我是可耻的分割线--------------------------- ...

  4. python写入sqlserver中文乱码问题

    需求是python3开发,数据库是sqlserver,第一次用python操作sqlserver,写入数据时,中文全部变成了?? 试了pyodbc,但缺少sqlserver驱动 试了sqlStr.en ...

  5. 4. python 文件操作

    文件打开有3种方式:读模式.写模式.追加模式 f = open('words','r',encoding='utf-8') #打开文件 print(f.read()) #读文件,读取之后文件指针放到最 ...

  6. dota中的哲理

    战术和战略: 6k分和3k分玩家的最重要的区别不是英雄玩的不好,而是整体战略不明确. dota玩家游戏时长超过1000h的比比皆是,这些玩家里面分数差距相当大.高的7k往上,低的2k深坑爬不出来. 这 ...

  7. FreeSql 将 Saas 租户方案精简到极致[.NET ORM]

    什么是多租户 维基百科:"软件多租户是指一种软件架构,在这种软件架构中,软件的一个实例运行在服务器上并且为多个租户服务".一个租户是一组共享该软件实例特定权限的用户.有了多租户架构 ...

  8. <连城诀>剧情大纲+随笔

    --剧情还是偷个懒,从百度百科抄袭一下,红色字体为补充和说明   在湘西沅陵南郊的麻溪乡下,三间小屋之前的晒谷场上,隐居此处多年的剑术名家"铁索横江"戚长发,看着徒弟狄云与女儿戚芳 ...

  9. Absolute Path Traversal 错误解决

    Absolute Path Traversal (APT) 是一种常见的安全漏洞,攻击者可以通过该漏洞访问应用程序的文件系统中的文件, 包括敏感信息,从而可能导致应用程序遭受攻击. 一.使用专门的文件 ...

  10. Debug --> python list.sort()食用方法

    list.sort(key=lambda x:x[1] , reverse=True) 参数 key 指明按照什么进行排序.lambda是匿名函数,参数的第一个x表示列表的第一个元素,如表示列表中的元 ...