微信公众号授权登录,整合spring security
公司的业务需求,对接了微信公众号授权,通过微信公众号的接口拿到用户信息进行业务系统的登录,话不多说上代码,我的实现方式是整合了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的更多相关文章
- 【tp5.1】微信公众号授权登录及获取信息录入数据库
微信公众号开发文档链接:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432 微信公众号授权登录分为两种: 1.以 ...
- 解决微信公众号授权登录和开放平台微信第三方应用授权登录获取到的用户Openid关联问题
开发背景: 最近一段时间一直在做关于微信方面的网站应用开发,这段时间也收获的不少关于微信开发方面的开发技能,接触的比较多的主要有微信公众号和微信网站app第三方登录授权,以及微信会员卡,优惠券和扫描二 ...
- uniapp - 微信公众号授权登录
[缘由] 采用uniapp进行微信小程序和微信公众号双版本开发:考虑到用户唯一性,我们后端确定了以“unionid”.作为唯一标识. 有的小伙伴估计也是刚入这坑,我就简单说一下步骤流程 [摸索] ...
- 微信公众号授权登录,提示“redirect_uri 参数错误”
做微信公众号开发授权登录的时候遇到的坑... 后台服务用node,index.js相关代码如下: const oauth = new OAuth(conf.appid, conf.appsecret) ...
- 微信公众号授权登录后报redirect_uri参数错误的问题
在进行微信公众号二次开发的时候,需要通过授权码模式来进行微信授权.比如,在进行登录的时候,用户点击了登录按钮,然后弹出一个授权框,用户点击同意后,就可以获取用户的OpenId等信息了.这篇文章主要 ...
- Chrome插件:微信公众号自动登录(chrome.extension)
manifest.json: { "manifest_version": 2, "name": "WX.AutoLogin", " ...
- 微信公众号授权,支付,退款总结【shoucang】
1.支付前准备 1.1首先两个平台接入账户. 商户平台:https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F 公众平台: ...
- PHP之路——微信公众号授权获取用户信息
官方文档链接:http://mp.weixin.qq.com/wiki/4/9ac2e7b1f1d22e9e57260f6553822520.html /** * 获取code */ public f ...
- 微信公众号授权回调用户信息,获取openid
1.--------------------用户授权登录并获取code 授权登录方式有两个,一种为静默授权登录(scope=snsapi_base),一种为非静默授权登录(scope=snsapi_u ...
- ASP.NET之MVC 微信公众号授权给第三方平台的技术实现流程(获取第三方平台access_token)
“出于安全考虑,在第三方平台创建审核通过后,微信服务器每隔10分钟会向第三方的消息接收地址推送一次component_verify_ticket,用于获取第三方平台接口调用凭据”.这是文档中的原话,也 ...
随机推荐
- Django中logging的设置
1.日志基础知识 日志与我们的软件程序密不可分.它记录了程序的运行情况,可以给我们调试程序和故障排查提供非常有用的信息.每一条日志信息记录了一个事件的发生.具体而言,它包括了: 事件发生时间 事件发生 ...
- 51nod1355
没啥意思的板子题. 首先,众所周知, \[\gcd\{f_a,f_b\}=f_{\gcd\{a,b\}} \] 所以考虑将 \(\operatorname{lcm}\) 转化为 \(\gcd\). \ ...
- threadlocal应用
public class DataSourceSelector { /** * 线程threadlocal */ private static ThreadLocal<String> db ...
- js 秒转时分秒
formateSeconds(endTime){ let secondTime = parseInt(endTime)//将传入的秒的值转化为Number let min = 0// 初始化分 let ...
- session共享问题、springboot 版本不统一问题
问题:按照正常的程序将session 共享引入工程,但是一直取不到 原因:springboot 的版本不同导致,存session的springboot 用的是springboot1.5.6,而取ses ...
- redis过期数据的底层存储结构
- 使用react脚手架创建项目报错-You are running `create-react-app` 5.0.0, which is behind the latest release (5.0.1).
创建项目报错: You are running `create-react-app` 5.0.0, which is behind the latest release (5.0.1). We no ...
- jquery获取父级容器高度
//获取浏览器显示区域的高度console.log( $(window).height()); //获取浏览器显示区域的宽度console.log($(window).width()); //获取页面 ...
- Coursera Programming Languages, Part B 华盛顿大学 Week 1
来上 programming language 的第二 part 了!这一部分介绍的语言是 Racket,之前就听说过它独特的括号语法,这次来具体了解一下 Racket definitions, fu ...
- MySQL之char、varchar、text类型
在存储字符串时, 可以使用char.varchar或者text类型, 那么具体使用场景呢? 参考下面这个表结构: 分析 一,char类型 char列的长度固定为创建表时声明的长度.长度可以为从0到25 ...