shiro-jwt登录认证流程

第一个链接多看

https://segmentfault.com/a/1190000014479154?utm_source=tag-newest

https://www.jianshu.com/p/6abc22ec3cb8

https://blog.csdn.net/mine_song/article/details/61616259

下边是关于过滤器和自定义过滤器的:

https://bbs.csdn.net/topics/392561505

https://www.cnblogs.com/woxbwo/p/11421685.html

https://www.cnblogs.com/XueTing/p/13734792.html

 

shiro+jwt做登录认证和授权认证,不要和我们登录功能搞混。我们的正常登录就是通过LoginControler登录的

而 shiro的登录认证是已经登录过后,每次访问资源时我们通过判断token证明该用户携带的token是合法的,授权类似。

很重要的总结。

1. 登录:

               ①LoginControler,找到登录请求 @RequestMapping("/login"),前端传来 LoginDto 的参数,包含用户名、密码; 根据前端传来的用户名查找数据库对应的用户user,如果用户不存在,则抛出异常用户名不存在; 否则查看密码是否      相等,相等则表示用户名和密码正确,我们为其生成token;

               ②生成token:通过 JwtUtils 工具类生成 token,通过userID生成jwt;

                                        JwtUtils 工具类主要有两个功能:

                                         生成token generateToken(long userId) 和解析读取token getClaimByToken(String token) 

 

                ③生成token后将其response.setHeader("Authorization",jwt)放入响应消息的头部,之后每次客户端头部携带token即可。

2. 那你携带token的请求后台如何认证? 就是之后每次都携带token,服务器如何识别和验证token,证明你是合法用户 每次携带token访问时,不在通过 LoginControler路径,这时候需要通过shiro+jwt做登录认证即可。

2. 登录之后,登录认证流程:

整体上流程是通过ShiroConfig包下的                                       顺序执行的,这也是shiroconfig配置三要素。

                                                    1、ShiroFilterFactoryBean                                           过滤器

                                                    2、DefaultWebSecurityManager                               安全管理组

                                                    3、创建UserRealm 对象,需自定义类                       Shiro与应用安全数据间(数据库)的“桥梁”或者“连接器”

(详细的是 ShiroConfig包下的ShiroFilterFactoryBean 到JwtFilter ,再到 ShiroConfig包下的DefaultWebSecurityManager,再到AccountRealm。)

          第一步:先找过滤器,先把我们自定义的过滤器放到shrio中,再把我们写的shiro内置的过滤器链放到shiro中。

         这是shiro内置的过滤器链写的内容:    

    @Bean //个人感觉:可以和过滤器合在一起写,比较直观。
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {  //shiro过滤器链,这里把过滤器声明链单独 拉出来  写,过滤器链可以写到shiroFilterFactoryBean中,过滤链定义,通过LinkedHashMap 保证从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); //过滤器链可以写内置的的过滤器,比如authc、perms等
        Map<String, String> filterMap = new LinkedHashMap<>();//为什么使用LinkedHashMap 是HashMap的一个子类,保存了记录的插入顺序,保证了自上而下匹配,而HashMap是无序的,部分路径无法拦截,或者时有时无。
        filterMap.put("/**", "jwt"); // 这里我们跳到jwt对应的 jwtFilter拦截器 进行 token 的有效性认证以及登录认证,如果登录认证返回ture,则再返回到这里

        chainDefinition.addPathDefinitions(filterMap);

        return chainDefinition;

 

 

 

第一步:JwtFilter包下的onAccessDenied方法,获得报文中的jwt,解析出jwt jwtUtils.getClaimByToken(jwt),得到如下jwt:

                         header={typ=JWT, alg=HS512},body={sub=7, iat=1620354034, exp=1620958834},signature=JAiLPfYv4cetlP1AX678ERwf4aPTUhEXONP9LhWTJrxjdB2PgcJvSVgIV4oXC0Cb7Ivb-_EPcet-C-NU3VJvnQ

                          我们都知道jwt由三部分组成:header、body(又叫载荷(Payload))、signature;

                        我们解析出body,初步判断jwt是否为空或者是否该jwt过期: if(claimByToken == null || jwtUtils.isTokenExpired(claimByToken.getExpiration()))

         第二步: 如果jwt正常,则执行登录认证:executeLogin(servletRequest,servletResponse); 这一步包含很多步骤:

executeLogin(servletRequest,servletResponse)  细说:

    executeLogin方法首先会调用creatToken方法,获得token,我们在 JwtFilter包里重写了方法,

我们将报文里的 jwt 转化成我们的JwtToken格式,其实都差不多。现在我们执行完  AuthenticationToken token = this.createToken(request, response);

如果为空,则报错,否则继续执行登录认证操作,接下来到这里:

Subject subject = this.getSubject(request, response);
subject.login(token);

执行subject.login(token),大致的说:这里之后会调用了 securityManager 的 login() 方法,然后走到 doAuthenticate() ,本质上就是调用 Realm 的方法,因此走到Realm。对应着从ShiroConfig的DefaultWebSecurityManager到AccountRealm

具体如何走的请参考:https://blog.csdn.net/saienenen/article/details/111028745

https://www.jianshu.com/p/6abc22ec3cb8

https://blog.csdn.net/qq_36816062/article/details/109030332?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control

 

                第三步:

通过简单的分析,明白了为什么 Springboot 应用使用需要 注入 DefaultWebSecurityManager,并且设置 自定义的 Realm。最终的 认证逻辑是交给 Realm 来执行的。

好了现在跳到 Realm上了:这一步才是真正执行  登录认证操作的,判断jwt的身份是否有效。首先判断用户名是否存在或者合法,再通过return new SimpleAuthenticationInfo(profile,jwtToken.getCredentials(),getName());判断密码是否正确

 

首先我们获得 jwt的用户名 jwtToken.getPrincipal(),这个可以看以下http://www.manongjc.com/detail/14-jmhshrgoycxclgz.html,我们在这分析下为什么 jwtToken.getPrincipal()得到的就是用户名,而getCredentials();得到的是密码

AuthenticationToken是最开始的抽象类,有getPrincipal()getCredentials()抽象方法,我们找到他的实现类UsernamePasswordToken

 

 

 

   密码的认证通过return new SimpleAuthenticationInfo(profile,jwtToken.getCredentials(),getName());实现,具体如何实现参考:

https://blog.csdn.net/hubeilihao/article/details/106414363

https://blog.51cto.com/luchunli/1830020

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值