认证流程

  1. 首先调用Subject.login(token)进行登录,其会自动委托给Security Manager,调用之前必须通过

    SecurityUtils. setSecurityManager()设置;

  2. SecurityManager负责真正的身份验证逻辑;它会委托给Authenticator进行身份验证;

  3. Authenticator才是真正的身份验证者,Shiro API中核心的身份认证入口点,此处可以自定义插入自己的实

    现;

  4. Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证,默认

    ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm身份验证;

  5. Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有返回/抛出异常表示身份

    验证失败了。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。

授权流程

  1. 首先调用Subject.isPermitted/hasRole接口,其会委托给SecurityManager,而SecurityManager接着会委托

    给Authorizer;

  2. Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过PermissionResolver

    把字符串转换成相应的Permission实例;

  3. 在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限;

  4. Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给

    ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted/hasRole会返回true,否则返回false表示

    授权失败。

 

1.自定义realms 类

  必须继承 AuthorizingRealm 抽象类

shiro 验证登录用JSESSIONID的弊端 shiro实现登陆_apache

shiro 验证登录用JSESSIONID的弊端 shiro实现登陆_数据_02

package com.zhao;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.util.ArrayList;
import java.util.List;

/**
 * 自定义realms 对象
 *  继承 AuthorizingRealm
 */
public class RealmDemo extends AuthorizingRealm {
    /**
     * 设置 RealmDemo 名字 ,自定义realms 对象 过多时避免重复
     * @param name
     */
    @Override
    public void setName(String name) {
        super.setName("realmDemo");
    }

    /**
     * 授权
     * 获取到用户的授权数据(用户的权限数据)
     * 根据认证的用户 获取到他的权限信息
     * @param principals 包含了所有的已认证的安全数据
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println(" 授权 AuthorizationInfo ");
        //1.获取安全数据 username ,有可能是用户id
        String primaryPrincipal = (String)principals.getPrimaryPrincipal();
        //2.根据 username  或者id查询用户
        //3.查询用户的角色 和权限信息
        //权限
        List<String> perms =new ArrayList<>();
        perms.add("user:save");
        perms.add("user:find");
        //角色
        List<String> roles =new ArrayList<>();
        roles.add("ordinary");
        roles.add("admin");
        //4.构造返回
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        //设置权限集合
        info.addStringPermissions(perms);
        //设置角色集合
        info.addRoles(roles);
        return info;
    }

    /**
     * 认证
     * 根据用户名密码进行登录,登录之后将用户数据进行保存
     * 认证的目的,比较用户名和密码是否与数据库中的一致
     * 将安全数据存入到shiro进行保管
     * @param authenticationToken 登录构造的 UsernamePasswordToken
     * @return AuthenticationInfo  授权数据
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println(" 认证 AuthenticationInfo ");
        //1. 构造  UsernamePasswordToken
        UsernamePasswordToken uptoken=(UsernamePasswordToken)authenticationToken;
        //2.获取输入的用户名密码
        String username = uptoken.getUsername();
        String password = new String(uptoken.getPassword());
        //3.根据用户名查询数据
        //4.比较密码和数据库中的密码是否一致(密码可能需要加密)
        if(username.equals("张三")&&password.equals("123456")){
            //5.成功 向 shiro存入数据
            /**
             * *@param principal与指定领域关联的“primary”主体。 安全数据
             * *@param credentials验证给定主体的凭据。    密码
             * *@param realmName从中获取主体和凭据的域。 当前realm 名称  getName()  获取到的是当前realm的名称 ,他的父类方法
             */
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username,password,getName());
            return  simpleAuthenticationInfo;
        }else {
            //6.失败 返回null 或者抛出 自定义的异常

            return null;
        }


    }
}

自定义realm类

2.配置文件

shiro 验证登录用JSESSIONID的弊端 shiro实现登陆_apache

shiro 验证登录用JSESSIONID的弊端 shiro实现登陆_数据_02

[main]
permRealm=com.zhao.RealmDemo
#注册realm到securityManager
securityManager.realms=$permRealm

View Code

3.测试

shiro 验证登录用JSESSIONID的弊端 shiro实现登陆_apache

shiro 验证登录用JSESSIONID的弊端 shiro实现登陆_数据_02

package com.zhao.shiro.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Before;
import org.junit.Test;

public class ShiroTest3 {
    @Before
    public void  init(){
        // 1.根据配置文件shiroDemo.ini 文件 创建 SecurityManagerFactor
        Factory<SecurityManager>  factory= new IniSecurityManagerFactory("classpath:shiroDemoRealm.ini");
        //2.通过工厂获取SecurityManager
        SecurityManager securityManager = factory.getInstance();
        //* 3.将SecurityManager绑定到当前运行环境
        SecurityUtils.setSecurityManager(securityManager);

    }

    /**
     * 测试用户登录
     * 用户认证
     * 1.根据配置文件shiroDemo.ini 文件 创建 SecurityManagerFactor
     * 2.通过工厂获取SecurityManager
     * 3.将SecurityManager绑定到当前运行环境
     * 4.从当前环境中构造subject
     * 5.构造shiro登陆的数据
     * 6.主题登录
     */
    @Test
    public void  login1(){
        //* 4.从当前环境中构造subject

        Subject subject = SecurityUtils.getSubject();
       //  * 5.构造用户认证的数据
//        String userName="lisi";
//        String password = "10086";
        String userName="张三";
       String password = "123456";
        UsernamePasswordToken token =new UsernamePasswordToken(userName,password);

        // * 6.主题登录
        //执行 login1--》realm 域中的认证方法
        subject.login(token);
       //登录之后完成授权 ,是否具有某个角色
        System.out.println(subject.hasRole("admin")); //是否有admin 这个角色
        System.out.println(subject.hasRole("root")); //是否有root 这个角色
        System.out.println(subject.isPermitted("user:save"));// 是否有 user:save 这个权限
    }
    
}

View Code