天天看點

shiro的具體認證流程

shiro的具體認證流程
以後一般繼承 AuthorizingRealm(授權)即可;其繼承了 AuthenticatingRealm(即身份驗證),而且也間接繼承了 CachingRealm(帶有緩存實作)
           
package com.baizhi.springboot_shiro.shiro.realms;

import com.baizhi.springboot_shiro.entity.Perms;
import com.baizhi.springboot_shiro.entity.Role;
import com.baizhi.springboot_shiro.entity.User;
import com.baizhi.springboot_shiro.service.UserService;
import com.baizhi.springboot_shiro.shiro.salt.MyByteSource;
import com.baizhi.springboot_shiro.utils.ApplicationContextUtil;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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 org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.List;

public class CustomerRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("調用授權驗證");
        //擷取身份資訊
        String primaryPrincipal = (String) principals.getPrimaryPrincipal();
        //根據主審分資訊擷取角色和權限
        UserService userService = (UserService) ApplicationContextUtil.getBean("userService");
        User user = userService.findRolesByUserName(primaryPrincipal);
        if (!CollectionUtils.isEmpty(user.getRoles())){
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            user.getRoles().forEach(role -> {
             simpleAuthorizationInfo.addRole(role.getName());

                //權限資訊
                List<Perms> perms = userService.findPermsByRoleId(role.getId());
                if (!CollectionUtils.isEmpty(perms)){
                    perms.forEach(perm -> {
                        simpleAuthorizationInfo.addStringPermission(perm.getName());
                    });
                }
            });
            return simpleAuthorizationInfo;
        }
//        if ("xiaochen".equals(primaryPrincipal)){
//            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//            simpleAuthorizationInfo.addRole("admin");
//            return simpleAuthorizationInfo;
//        }
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String principal = (String) token.getPrincipal();
        UserService userService = (UserService) ApplicationContextUtil.getBean("userService");
        User user = userService.findByUsername(principal);
        if (!ObjectUtils.isEmpty(user)) {
//            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), new MyByteSource(user.getSalt()), this.getName());
            return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), new MyByteSource(user.getSalt()),this.getName());
        }

        return null;
    }
}

           
  1. 自定義Realm繼承AuthorizingRealm
  2. 使用doGetAuthenticationInfo方法經行認證
  3. 通過傳入的token擷取principal使用者名
  4. 使用principal查找資料庫擷取user對象
  5. 調用SimpleAuthenticationInfo方法構造SimpleAuthenticationInfo對象并且傳回
  6. 最後自定義的Realm的父類AuthenticatingRealm執行getAuthenticationInfo方法中的assertCredentialsMatch進行密碼驗證
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        AuthenticationInfo info = getCachedAuthenticationInfo(token);
        if (info == null) {
            //otherwise not cached, perform the lookup:
            info = doGetAuthenticationInfo(token);
            log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
            if (token != null && info != null) {
                cacheAuthenticationInfoIfPossible(token, info);
            }
        } else {
            log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
        }

        if (info != null) {
            assertCredentialsMatch(token, info);
        } else {
            log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}].  Returning null.", token);
        }

        return info;
    }

           
protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
        CredentialsMatcher cm = getCredentialsMatcher();
        if (cm != null) {
            if (!cm.doCredentialsMatch(token, info)) {
                //not successful - throw an exception to indicate this:
                String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
                throw new IncorrectCredentialsException(msg);
            }
        } else {
            throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
                    "credentials during authentication.  If you do not wish for credentials to be examined, you " +
                    "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
        }
    }
           
shiro的具體認證流程

身份認證流程

shiro的具體認證流程
流程如下:

首先調用 Subject.login(token) 進行登入,其會自動委托給 Security Manager,調用之前必須通過 SecurityUtils.setSecurityManager() 設定;
SecurityManager 負責真正的身份驗證邏輯;它會委托給 Authenticator 進行身份驗證;
Authenticator 才是真正的身份驗證者,Shiro API 中核心的身份認證入口點,此處可以自定義插入自己的實作;
Authenticator 可能會委托給相應的 AuthenticationStrategy 進行多 Realm 身份驗證,預設 ModularRealmAuthenticator 會調用 AuthenticationStrategy 進行多 Realm 身份驗證;
Authenticator 會把相應的 token 傳入 Realm,從 Realm 擷取身份驗證資訊,如果沒有傳回 / 抛出異常表示身份驗證成功了。此處可以配置多個 Realm,将按照相應的順序及政策進行通路。
           

參考他人的方法

https://blog.csdn.net/a739260008/article/details/108457418

參考他人的csdn添加連結描述