微信小程序实现token登录
微信小程序登录流程
前端先调用wx.login()
接口获取code,再把code发个后端
login() {
wx.login({
success: (res) => {
wx.request({
url:"/login",
method:"POST",
data:{
code:res
},
dataType:'json'
})
},
})
}
后端采用是SpringSecurity+jwt+redis
@RestController
public class LoginController {
@Autowired
LoginService loginService;
@PostMapping("/login")
public R<Map<String,Object>> login(@RequestBody Map<String, String> params) {
String code = params.get("code");
if (StringUtils.isBlank(code)) {
throw new ValidateException("code不能为空");
}
return loginService.login(code);
}
}
后端接收code之后再发送http到微信官方获得openid
@Component
@ConfigurationProperties(prefix = "wx")
@Data
public class WxLogin {
private String appid;
private String secret;
private String grant_type;
private String wxurl;
public String getOpenId(String code) throws IOException, URISyntaxException {
URL url = new URL(wxurl);
URI uri = new URIBuilder().setScheme(url.getProtocol())
.setHost(url.getHost())
.setPort(url.getPort())
.setPath(url.getPath())
.setParameters(
new BasicNameValuePair("appid",appid),
new BasicNameValuePair("secret",secret),
new BasicNameValuePair("js_code",code),
new BasicNameValuePair("grant_type",grant_type)
).build();
HttpGet httpGet = new HttpGet(uri);
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
// 配置信息
RequestConfig requestConfig = RequestConfig.custom()
// 设置连接超时时间(单位毫秒)
.setConnectTimeout(5000)
// 设置请求超时时间(单位毫秒)
.setConnectionRequestTimeout(5000)
// socket读写超时时间(单位毫秒)
.setSocketTimeout(5000)
// 设置是否允许重定向(默认为true)
.setRedirectsEnabled(true).build();
httpGet.setConfig(requestConfig);
//响应
CloseableHttpResponse response = httpClient.execute(httpGet);
// 从响应模型中获取响应实体
String openId = null;
try {
HttpEntity responseEntity = response.getEntity();
// System.out.println("响应状态为:" + response.getStatusLine());
if (StringUtils.isNull(responseEntity)) {
throw new WxLoginException("响应体为空");
}
// System.out.println("响应内容长度为:" + responseEntity.getContentLength());
// System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
JSONObject json = JSON.parseObject(EntityUtils.toString(responseEntity));
openId = json.getString("openid");
if (StringUtils.isNull(openId)) {
throw new WxLoginException("openid重复使用");
}
} finally {
httpClient.close();
response.close();
}
return openId;
}
}
通过opid查询数据库进行登录注册。
springsecurity登录流程
@Service
public class LoginServiceImpl implements LoginService {
@Autowired
private WxLogin wxLogin;
@Autowired
private UserService userService;
@Autowired
private RedisCache redisCache;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private TokenService tokenService;
@Override
public R<Map<String, Object>> login(String code) {
//得到openID
String openId = null;
try {
openId = wxLogin.getOpenId(code);
} catch (IOException | URISyntaxException e) {
e.printStackTrace();
return R.fail(HttpStatus.ERROR,"服务器请求异常");
}
//查询数据库是否存在openID
boolean exist = true;
//先查缓存再查数据库
LoginUser loginUser = redisCache.getCacheObject(RedisCacheKeys.USERINFO_KEY + openId);
if (StringUtils.isNull(loginUser)) {
loginUser = new LoginUser();
}
if (StringUtils.isNull(loginUser.getUser())) {
LambdaQueryWrapper<User> uqw = new LambdaQueryWrapper<>();
uqw.eq(User::getOpenid,openId);
User user = userService.getOne(uqw);
if (StringUtils.isNull(user)) {
exist = false;
} else {
loginUser.setUser(user);
redisCache.setCacheObject(RedisCacheKeys.USERINFO_KEY+openId, loginUser);
}
}
//不存在就注册,再登录
if(!exist) {
register(openId);
}
//springsecurity进行登录,存在就登录
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(openId, "null");
Authentication authenticate = authenticationManager.authenticate(authenticationToken);
if (StringUtils.isNull(authenticate)) {
throw new UsernameNotFoundException("用户名不出在!");
}
//封装
LoginUser user = (LoginUser) authenticate.getPrincipal();
//生成token
String token = tokenService.createToken(user);
UserInfoVo userInfo = BeanUtils.copyBean(loginUser.getUser(),UserInfoVo.class);
HashMap<String, Object> res = new HashMap<String, Object>();
res.put("token",token);
res.put("userInfo",userInfo);
return R.ok(res);
}
@Override
public void register(String openId) {
//
User user = new User();
user.setOpenid(openId);
userService.save(user);
}
}
token生成
@Component
public class TokenService
{
// 令牌自定义标识
@Value("${token.header}")
private String header;
// 令牌秘钥
@Value("${token.secret}")
private String secret;
// 令牌有效期(默认30分钟)
@Value("${token.expireTime}")
private int expireTime;
protected static final long MILLIS_SECOND = 1000;
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
protected static final long MILLIS_HOURS = 60 * MILLIS_MINUTE;
private static final Long MILLIS_MINUTE_TEN = 60 * 60 * 1000L;
@Autowired
private RedisCache redisCache;
/**
* 获取用户身份信息
*
* @return 用户信息
*/
public LoginUser getLoginUser(HttpServletRequest request)
{
// 获取请求携带的令牌
String token = getToken(request);
if (StringUtils.isNotEmpty(token))
{
try
{
Claims claims = parseToken(token);
// 解析对应的权限以及用户信息
String openid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(openid);
return redisCache.getCacheObject(userKey);
}
catch (Exception e)
{
e.printStackTrace();
}
}
return null;
}
/**
* 删除用户身份信息
*/
public void delLoginUser(String token)
{
if (StringUtils.isNotEmpty(token))
{
String userKey = getTokenKey(token);
redisCache.deleteObject(userKey);
}
}
/**
* 创建令牌
*
* @param loginUser 用户信息
* @return 令牌
*/
public String createToken(LoginUser loginUser)
{
refreshToken(loginUser);
Map<String, Object> claims = new HashMap<>();
claims.put(Constants.LOGIN_USER_KEY, loginUser.getUser().getOpenid());
return createToken(claims);
}
/**
* 验证令牌有效期,相差不足一个小时,自动刷新缓存
*
* @param loginUser
* @return 令牌
*/
public void verifyToken(LoginUser loginUser)
{
long expireTime = loginUser.getExpireTime();
long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
{
refreshToken(loginUser);
}
}
/**
* 刷新令牌有效期
*
* @param loginUser 登录信息
*/
public void refreshToken(LoginUser loginUser)
{
loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_HOURS);
// 根据uuid将loginUser缓存
String userKey = getTokenKey(loginUser.getUser().getOpenid());
redisCache.setCacheObject(userKey, loginUser,
expireTime,TimeUnit.HOURS);
}
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
private String createToken(Map<String, Object> claims)
{
return Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret).compact();
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
private Claims parseToken(String token)
{
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
/**
* 从令牌中获取用户名
*
* @param token 令牌
* @return 用户名
*/
public String getUsernameFromToken(String token)
{
Claims claims = parseToken(token);
return claims.getSubject();
}
/**
* 获取请求token
*
* @param request
* @return token
*/
private String getToken(HttpServletRequest request)
{
return request.getHeader(header);
}
private String getTokenKey(String openId)
{
return RedisCacheKeys.USERINFO_KEY + openId;
}
}
完整流程图
**
* 获取请求token
*
* @param request
* @return token
*/
private String getToken(HttpServletRequest request)
{
return request.getHeader(header);
}文章来源:https://www.toymoban.com/news/detail-563195.html
private String getTokenKey(String openId)
{
return RedisCacheKeys.USERINFO_KEY + openId;
}
}文章来源地址https://www.toymoban.com/news/detail-563195.html
完整流程图
[外链图片转存中...(img-KPgnRjWY-1678029553423)]
到了这里,关于微信小程序实现token登录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!