使用Shiro+JWT完成的微信小程序的登录(含讲解)

本文介绍了一个使用Shiro和JWT实现微信小程序登录的项目,详细讲解了项目的流程、结构及具体实现。首先,你需要了解微信小程序登录流程、Shiro基础知识和JWT原理。项目流程包括获取code,调用login接口,Shiro拦截器验证token,以及登录配置。项目结构包括配置、异常处理、JWT工具类、Shiro配置和登录服务。在Shiro配置中,自定义realm,关闭session,实现JWT工具类和拦截器,完成登录处理。最后,提供了登录配置的实现,包括controller、loginService和SpringHttp工具类RestTemplate的使用。
摘要由CSDN通过智能技术生成

源码地址https://github.com/Jirath-Liu/shiro-jwt-wx

微信小程序用户登陆,完整流程可参考下面官方地址,本例中是按此流程开发
https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

你需要了解的点

微信小程序的登录流程

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

Shiro的基础知识

https://shiro.apache.org/10-minute-tutorial.html

JWT以及Token

https://jwt.io/introduction/

项目的流程

未命名文件

  1. 调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。
  2. 访问login接口,并将code给后台
  3. 被JwtShirioFilter拦截(在shiro配置中配置的),查看有没有token在Header
  4. 有则自动执行登录操作,核实token的合法性,并刷新token
  5. 没有则被controller拦截进入service中进行登录
  6. 使用code获取用户信息,默认初始化了一些信息(可以修改的)
  7. 生成token(会存至redis)
  8. 返回token

本项目的结构

项目分包:

  1. conf 项目的配置
    • exceptoionconfig 配置了异常的抛出,使用@ControllerAdvice进行拦截统一处理
    • jwt 包含一个jwt工具类,在使用时会与redis连接,存储、验证与生成token
    • shiro 是本项目配置的核心,其中关闭了session管理,使用jwt来完成验证,包含一个自定的应用于shiro的token
    • RestTemplateConfig 使用Spring
  2. enums 包含了需要的枚举类
  3. vo
    • wxapi 包含了一个请求微信后台需要的结果类

不可修改的模块:有JWT与Shiro的类别以及配置模块

具体实现

一、shiro基础配置

1.设置一个自己的realm进行token验证,用户登录会执行你的realm

在DefaultWebSecurityManager 中进行配置

realm是需要自己实现的,先让他在这里报错,当自己的提示也可以

DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager(tokenRealm);
        //设置realm
        defaultWebSecurityManager.setRealm(tokenRealm);

2.我们需要关闭shiro的session功能

在DefaultWebSecurityManager 中进行配置

 DefaultSubjectDAO subjectDAO = (DefaultSubjectDAO) defaultWebSecurityManager.getSubjectDAO();
        DefaultSessionStorageEvaluator evaluator = (DefaultSessionStorageEvaluator) subjectDAO.getSessionStorageEvaluator();
        evaluator.setSessionStorageEnabled(Boolean.FALSE)

3.设置realm

我们需要定制一个realm,并且为了能够被识别,选择继承AuthorizingRealm类

需要我们完成的模块:

  1. realm对请求的识别 我们的方案是验证token是否为我们定制的token
  2. 审核信息 其中有对token的验证,我们做在工具类中
  3. 身份/角色验证
  4. 关闭密码校验加密
@Component
public class TokenRealm extends AuthorizingRealm {
   
    @Autowired
    JwtUtil jwtUtil;

    /**
     * 该方法是为了判断这个主体能否被本Realm处理,判断的方法是查看token是否为同一个类型
     * @param authenticationToken
     * @return
     */
    @Override
    public boolean supports(AuthenticationToken authenticationToken) {
   
        return authenticationToken instanceof JwtShiroToken;
    }


    /**
     * 在需要验证身份进行登录时,会通过这个接口,调用本方法进行审核,将身份信息返回,有误则抛出异常,在外层拦截
     * @param authenticationToken 这里收到的是自定义的token类型,在JwtShiroToken中,自动向上转型。得到的getCredentials为String类型,可以使用toString
     * @return
     * @throws AuthenticationException token异常,可以细化设置
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
   
        String submittedToken=authenticationToken.getCredentials().toString();
        //解析出信息
        String wxOpenId = jwtUtil.getWxOpenIdByToken(submittedToken);
        String sessionKey = jwtUtil.getSessionKeyByToken(submittedToken);
        String userId=jwtUtil.getUserIdByToken(submittedToken);
        //对信息进行辨别
        if (StringUtils.isEmpty(wxOpenId)) {
   
            throw new TokenException("user account not exits , please check your token");
        }
        if (StringUtils.isEmpty(sessionKey)) {
   
            throw new TokenException("sessionKey is invalid , please check your token");
        }
        if (StringUtils.isEmpty(userId)) {
   
            throw new TokenException("userId is invalid , please check your token");
        }
        if (!jwtUtil.verifyToken(submittedToken)) {
   
            throw new TokenException("token is invalid , please check your token");
        }
        //在这里将principal换为用户的id
        return new SimpleAuthenticationInfo(userId, submittedToken, getName());
    }

    /**
     * 这个方法是用来添加身份信息的,本项目计划为管理员提供网站后台,所以这里不需要身份信息,返回一个简单的即可
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
   
        return null;
    }

    /**
     * 注意坑点 : 密码校验 , 这里因为是JWT形式,就无需密码校验和加密,直接让其返回为true(如果不设置的话,该值默认为false,即始终验证不通过)
     */
    @Override
    public CredentialsMatcher getCredentialsMatcher() {
   
        return (token, info) -> true;
    }
}

4.定制一个token,继承AuthenticationToken

默认的token是包含两个部分的,账号和密码(可以这样理解)

我们将这两个信息都调整为token

/**
 * @author Jirath
 * @date 2020/4/9
 * @description: 一个用于Shiro使用的Authentication,因为使用JWT需要有自己的身份信息,所以使用针对Token定制的信息
 */
@Data
public class JwtShiroToken implements AuthenticationToken {
   
    /**
     * 封装,防止误操作
     */
    private String token;

    /**
     * token作为两者进行提交,使用构造方法进行初始化
     * @param token 用户提交的token
     */
    public JwtShiroToken(String token){
   
        this.token=token;
    }
    /**
     * 在UserNamePasswordToken中,使用的是账号和密码来作为主体和签证,这里我们使用Token登录
     * 两者的get都是获取token
     */
    @Override
    public Object getPrincipal() {
   
        return token;
    }

    @Override
    public Object getCredentials(
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值