shiro实现权限校验和session共享


1. ShiroRealm 授权/认证

import java.util.List;

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.authc.UsernamePasswordToken;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.huawei.hicloud.service.UserService;

/**
 * 认证/授权
 * 
 * @author
 *
 */
public class MyShiroRealm extends AuthorizingRealm {

	private static final Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);

	@Autowired
	private UserService userService;

	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
		logger.info("##### doGetAuthorizationInfo args: " + principalCollection);
		
		// 获取用户名
		String username = (String) principalCollection.getPrimaryPrincipal();

		// 通过用户名获取用户权限信息
		SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
		List<String> roles = userService.getRoles(username);
		simpleAuthorizationInfo.addRoles(roles);
		for (String role : roles) {
			List<String> permissions = userService.getPermissions(role);
			simpleAuthorizationInfo.addStringPermissions(permissions);
		}

		return simpleAuthorizationInfo;
	}

	/**
	 * 登录认证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
			throws AuthenticationException {
		logger.info("##### doGetAuthenticationInfo args: " + authenticationToken);

		UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
		// 获取登录信息
		String userName = token.getUsername();
		char[] password = token.getPassword();
		
		// 查询数据库获取用户信息,校验密码,判断用户状态
		
		// 加入判断逻辑
		

		SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName, password,
				ByteSource.Util.bytes(userName), getName());

		return authenticationInfo;
	}

}

2. SessionManager

import java.io.Serializable;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.util.StringUtils;

public class MySessionManager extends DefaultWebSessionManager {
	private static final String AUTHORIZATION = "X-Auth-Token";

	private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";

	public MySessionManager() {
		super();
	}

	@Override
	protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
		String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
		// 如果请求头中有Authorization则其值为sessionId
		if (!StringUtils.isEmpty(id)) {
			request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
			request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
			request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
			
			return id;
		} else {
			// 否则按默认规则从cookie取sessionId
			return super.getSessionId(request, response);
		}
	}
}

3. SessionDao重写session增删改查实现

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.fastjson.JSON;
import com.huawei.hicloud.components.jedis.JedisClient;

public class RedisSessionDao extends EnterpriseCacheSessionDAO {

	private static final Logger logger = LoggerFactory.getLogger(RedisSessionDao.class);
	
	/** Session过期时间,单位: 秒 */
	private static final Integer SESSION_TIMEOUT = 30*60;

	@Autowired
	private JedisClient jedisClient;

	// 创建session,保存到数据库
	@Override
	protected Serializable doCreate(Session session) {
		logger.info("### doCreate session: " + JSON.toJSONString(session));
		Serializable sessionId = super.doCreate(session);
		byte[] key = sessionId.toString().getBytes();
		jedisClient.set(key, sessionToByte(session));
		jedisClient.expire(key, SESSION_TIMEOUT);

		return sessionId;
	}

	// 获取session
	@Override
	protected Session doReadSession(Serializable sessionId) {
		logger.info("### doReadSession sessionId: {}", sessionId);

		// 先从缓存中获取session,如果没有再去数据库中获取
		Session session = super.doReadSession(sessionId);
		if (session == null) {
			byte[] key = sessionId.toString().getBytes();
			byte[] bytes = jedisClient.get(key);
			if (bytes != null && bytes.length > 0) {
				session = byteToSession(bytes);
			}
			jedisClient.expire(key, SESSION_TIMEOUT);
		}
		
		return session;
	}

	// 更新session的最后一次访问时间
	@Override
	protected void doUpdate(Session session) {
		logger.info("### doUpdate session: " + JSON.toJSONString(session));
		super.doUpdate(session);
		byte[] key = session.getId().toString().getBytes();
		jedisClient.set(key, sessionToByte(session));
		jedisClient.expire(key, SESSION_TIMEOUT);
	}

	// 删除session
	@Override
	protected void doDelete(Session session) {
		logger.info("### doDelete session: " + JSON.toJSONString(session));
		super.doDelete(session);
		jedisClient.del(session.getId().toString().getBytes());
	}

	// 把session对象转化为byte保存到redis中
	public byte[] sessionToByte(Session session) {
		ByteArrayOutputStream bo = new ByteArrayOutputStream();
		byte[] bytes = null;
		try {
			ObjectOutputStream oo = new ObjectOutputStream(bo);
			oo.writeObject(session);
			bytes = bo.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return bytes;
	}

	// 把byte还原为session
	public Session byteToSession(byte[] bytes) {
		ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
		ObjectInputStream in;
		SimpleSession session = null;
		try {
			in = new ObjectInputStream(bi);
			session = (SimpleSession) in.readObject();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return session;
	}

}
4. ShiroConfiguration
import java.util.LinkedHashMap;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.huawei.hicloud.components.shiro.MySessionManager;
import com.huawei.hicloud.components.shiro.MyShiroRealm;
import com.huawei.hicloud.components.shiro.RedisSessionDao;

@Configuration
public class ShiroConfiguration {

	/**
	 * Realm认证/授权加入容器管理
	 * @return
	 */
	@Bean
	public MyShiroRealm myShiroRealm() {
		MyShiroRealm myShiroRealm = new MyShiroRealm();
		
		return myShiroRealm;
	}
	
	/**
	 * Redis实现session共享
	 * @return
	 */
	@Bean
	public RedisSessionDao redisSessionDao() {
		
		return new RedisSessionDao();
	}

	/**
	 * SessionManager
	 * 自定义SessionDAO实例,实现session共享
	 * @return
	 */
	@Bean
	public SessionManager sessionManager() {
		MySessionManager mySessionManager = new MySessionManager();
		mySessionManager.setSessionDAO(redisSessionDao());
		mySessionManager.setGlobalSessionTimeout(30 * 60 * 1000);
		
		return mySessionManager;
	}

	/**
	 * SecurityManager
	 * 权限/认证/session/缓存
	 * @return
	 */
	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(myShiroRealm());
		securityManager.setSessionManager(sessionManager());
		//securityManager.setCacheManager(cacheManager);

		return securityManager;
	}

	/**
	 * Shiro filter工厂
	 * @param securityManager
	 * @return
	 */
	@Bean
	public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);

		LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		// 登出
		filterChainDefinitionMap.put("/logout", "logout");
		// 配置不会被拦截的链接 顺序判断
		filterChainDefinitionMap.put("/static/**", "anon");
		filterChainDefinitionMap.put("/ajaxLogin", "anon");
		filterChainDefinitionMap.put("/login", "anon");
		// 所有url都需认证
		filterChainDefinitionMap.put("/**", "authc");

		// 登录
		shiroFilterFactoryBean.setLoginUrl("/login");
		// 首页
		shiroFilterFactoryBean.setSuccessUrl("/index");
		// 错误页面,认证不通过跳转
		shiroFilterFactoryBean.setUnauthorizedUrl("/error");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

		return shiroFilterFactoryBean;
	}

	/**
	 * 开启shiro注解
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);

		return authorizationAttributeSourceAdvisor;
	}

	@Bean
	@ConditionalOnMissingBean
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
		defaultAAP.setProxyTargetClass(true);
		
		return defaultAAP;
	}

}

5. 登录测试

到Realm里面实现认证

import java.util.HashMap;
import java.util.Map;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LoginController {

	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public Map<String, Object> login(@RequestBody Map<String, String> params) {
		HashMap<String, Object> result = new HashMap<>();

		Subject subject = SecurityUtils.getSubject();
		UsernamePasswordToken token = new UsernamePasswordToken("shiro", "123456");

		try {
			subject.login(token);
			result.put("token", subject.getSession().getId() + "");
			result.put("msg", "登录成功");
		} catch (IncorrectCredentialsException e) {
			result.put("msg", "密码错误");
		} catch (LockedAccountException e) {
			result.put("msg", "登录失败,该用户已被冻结");
		} catch (AuthenticationException e) {
			result.put("msg", "该用户不存在");
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

}

6. 授权测试

import java.util.HashMap;
import java.util.Map;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ShiroController {

	@RequiresRoles("admin")
	@RequiresPermissions("rs:view")
	@RequestMapping(value="/shiro", method=RequestMethod.GET)
	public Map<String, Object> shiro() {
		HashMap<String, Object> resultMap = new HashMap<>();
		
		resultMap.put("msg", "Hello shiro!");
		
		return resultMap;
	}
	
}



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值