shiro实现权限校验和session共享
2018-03-25 13:53
239 查看
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. SessionManagerimport 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
到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;
}
}
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. SessionManagerimport 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; } /** * Securi 4000 tyManager * 权限/认证/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;
}
}
相关文章推荐
- Hello Mr.J——shiro 实现session共享
- spring+shiro+redis实现session共享
- shiro 实现自定义权限规则校验
- Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享
- C/S,APP架构中,通过shiro重写session,用shiro实现权限管理?
- spring+redis+shiro 实现session共享
- Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享
- spring,shiro,redis实现session共享
- SpringBoot+redis 实现shiro集群,共享session。亲测可用
- Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享
- Shiro+Redis实现tomcat集群session共享
- shiro- session,自定义FormAuthenticationFilter(表单认证器)-->实现验证码校验
- Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享
- apache shiro集群实现(一) session共享
- jeesite shiro+redis实现cache和session共享
- 类Shiro权限校验框架的设计和实现(2)--对复杂权限表达式的支持
- hiro教程(六)Shiro Session共享配置以及实现
- Shiro 分布式架构下 Session 的共享实现
- apache shiro集群实现(一) session共享
- 在前后端分离的项目中,后台使用shiro框架时,怎样使用它的会话管理系统(session),从而实现权限控制