针对用户身份权限管理包含账户权限登录认证+会话保持两个部分,在 移动端+服务平台 或 前后端分离 的项目框架下,一般会涉及到通过token来进行用户登录会话的保持。
以下我将通过在HTTP Header中增加token的方式在RestfulApi的服务端进行权限校验与会话保持。
org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO org.apache.shiro.web.session.mgt.DefaultWebSessionManager
public class TokenSessionManager extends DefaultWebSessionManager {
public static final String ACCESS_TOKEN = "x-access-token";
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
final String accessToken = WebUtils.toHttp(request).getHeader(this.ACCESS_TOKEN);
if (StringUtils.isBlank(accessToken)) {
return null;
}
// 设置当前session状态
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, accessToken);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return accessToken;
}
}
@Component
public class RedisSessionDAO extends EnterpriseCacheSessionDAO {
@Resource
private RedisTemplate<String, String> redisTemplate;
public RedisSessionDAO(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public RedisTemplate<String, String> getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
protected Session doReadSession(Serializable serializable) {
final Object validAccessToken = redisTemplate.opsForHash().get(RedisConst.REDIS_ACCESS_TOKEN_KEY, serializable);
if (validAccessToken == null) {
return null;
}
final SimpleSession simpleSession = new SimpleSession();
simpleSession.setId(serializable);
final SysUser sysUser = JSON.parseObject(validAccessToken.toString(), SysUser.class);
simpleSession.setAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY, new SimplePrincipalCollection(sysUser, "authorRealm"));
simpleSession.setAttribute(DefaultSubjectContext.AUTHENTICATED_SESSION_KEY, Boolean.TRUE);
return simpleSession;
}
@Override
protected void doUpdate(Session session) {
PrincipalCollection existingPrincipals = (PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
if (existingPrincipals == null) {
return;
}
final Object primaryPrincipal = existingPrincipals.getPrimaryPrincipal();
if (primaryPrincipal instanceof SysUser) {
final SysUser sysUser = (SysUser)primaryPrincipal;
redisTemplate.opsForHash().put(RedisConst.REDIS_ACCESS_TOKEN_KEY, session.getId(), JSON.toJSONString(sysUser));
}
}
@Override
protected void doDelete(Session session) {
redisTemplate.opsForHash().delete(RedisConst.REDIS_ACCESS_TOKEN_KEY, session.getId());
}
}
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" p:realm-ref="authorRealm">
<property name="cacheManager">
<bean class="org.apache.shiro.cache.ehcache.EhCacheManager" />
</property>
<property name="sessionManager">
<bean class="org.wujianjun.apps.web.auth.TokenSessionManager" p:sessionDAO-ref="redisSessionDAO"
p:deleteInvalidSessions="false" p:sessionIdCookieEnabled="false" p:sessionValidationSchedulerEnabled="false"/>
</property>
</bean>
观点仅代表自己,期待你的留言。