package com.ruoyi.framework.shiro.realm;

import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.platform.PlatformUser;
import com.ruoyi.common.core.domain.platform.vo.PlatformUserVO;
import com.ruoyi.common.enums.LoginType;
import com.ruoyi.common.exception.user.*;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.common.utils.bean.DozerUtils;
import com.ruoyi.framework.shiro.realm.token.CustomToken;
import com.ruoyi.framework.shiro.service.SysLoginService;
import com.ruoyi.platform.service.IPlatformMenuService;
import com.ruoyi.platform.service.IPlatformRoleService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashSet;
import java.util.Set;

/**
 *@Description 自定义平台Realm 处理登录 权限
 *@Author zhushuyong
 *@Date 2021/6/24 17:28
 *@since:
 *@copyright: 版权所有2021 开源组织 gitee(https://gitee.com/jinzheyi)作者：朱述勇<br/>
 *            GitHub(https://github.com/jinzheyi)作者：朱述勇 。
 */
public class PlatformUserRealm extends AuthorizingRealm
{
    private static final Logger log = LoggerFactory.getLogger(PlatformUserRealm.class);

    @Autowired
    private IPlatformMenuService platformMenuService;

    @Autowired
    private IPlatformRoleService platformRoleService;

    @Autowired
    private SysLoginService loginService;

    @Override
    public String getName() {
        return LoginType.PLATFORM_USER.getType();
    }

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)
    {
        //校验正确的当前用户
        if (!getName().equals(principalCollection.getRealmNames().stream().findFirst().get())) {
            return null;
        }
        PlatformUserVO user = ShiroUtils.getPlatformUser();
        // 角色列表
        Set<String> roles = new HashSet<String>();
        // 功能列表
        Set<String> menus = new HashSet<String>();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 平台超级管理员拥有所有权限
        if (DozerUtils.copyProperties(user, PlatformUser.class).isAdmin())
        {
            info.addRole(Constants.PLATFORM_ADMIN);
            info.addStringPermission("*:*:*");
        }
        else
        {
            roles = platformRoleService.selectRoleKeys(user.getId());
            menus = platformMenuService.selectPermsByUserId(user.getId());
            // 角色加入AuthorizationInfo认证对象
            info.setRoles(roles);
            // 权限加入AuthorizationInfo认证对象
            info.setStringPermissions(menus);
        }
        return info;
    }

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
    {
        CustomToken upToken = (CustomToken) token;
        PlatformUserVO user = null;
        try
        {
            user = loginService.platformLogin(upToken);
        }
        catch (CaptchaException e)
        {
            throw new AuthenticationException(e.getMessage(), e);
        }
        catch (UserNotExistsException e)
        {
            throw new UnknownAccountException(e.getMessage(), e);
        }
        catch (UserPasswordNotMatchException e)
        {
            throw new IncorrectCredentialsException(e.getMessage(), e);
        }
        catch (UserPasswordRetryLimitExceedException e)
        {
            throw new ExcessiveAttemptsException(e.getMessage(), e);
        }
        catch (UserBlockedException e)
        {
            throw new LockedAccountException(e.getMessage(), e);
        }
        catch (RoleBlockedException e)
        {
            throw new LockedAccountException(e.getMessage(), e);
        }
        catch (Exception e)
        {
            log.info("对用户[" + upToken.getUsername() + "]进行登录验证..验证未通过{}", e.getMessage());
            throw new AuthenticationException(e.getMessage(), e);
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, upToken.getPassword(), getName());
        return info;
    }

    /**
     * 清理指定用户授权信息缓存
     */
    public void clearCachedAuthorizationInfo(Object principal)
    {
        SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
        this.clearCachedAuthorizationInfo(principals);
    }

    /**
     * 清理所有用户授权信息缓存
     */
    public void clearAllCachedAuthorizationInfo()
    {
        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
        if (cache != null)
        {
            for (Object key : cache.keys())
            {
                cache.remove(key);
            }
        }
    }
}
