Shiro框架学习笔记(一)

#Shiro框架学习笔记(一)

#############################################################################
###一、sessionValidationScheduler的使session失效执行流程(SessionManeger)###
#############################################################################
1.ExecutorServiceSessionValidationScheduler
    
    public void run() {
        if (log.isDebugEnabled()) {
            log.debug("Executing session validation...");
        }

        long startTime = System.currentTimeMillis();
        
        //(1)调用AbstractValidatingSessionManager.validateSessions()方法
        this.sessionManager.validateSessions();
        
        long stopTime = System.currentTimeMillis();
        if (log.isDebugEnabled()) {
            log.debug("Session validation completed successfully in " + (stopTime - startTime) + " milliseconds.");
        }

    }

2.AbstractValidatingSessionManager.validateSessions()方法

    public void validateSessions() {
        if (log.isInfoEnabled()) {
            log.info("Validating all active sessions...");
        }

        int invalidCount = 0;
        Collection<Session> activeSessions = this.getActiveSessions();
        if (activeSessions != null && !activeSessions.isEmpty()) {
            Iterator i$ = activeSessions.iterator();

            while(i$.hasNext()) {
                Session s = (Session)i$.next();

                try {
                    SessionKey key = new DefaultSessionKey(s.getId());
                    
                    //(2)调用validate()方法
                    this.validate(s, key);
                    
                } catch (InvalidSessionException var8) {
                    if (log.isDebugEnabled()) {
                        boolean expired = var8 instanceof ExpiredSessionException;
                        String msg = "Invalidated session with id [" + s.getId() + "]" + (expired ? " (expired)" : " (stopped)");
                        log.debug(msg);
                    }

                    ++invalidCount;
                }
            }
        }

        if (log.isInfoEnabled()) {
            String msg = "Finished session validation.";
            if (invalidCount > 0) {
                msg = msg + "  [" + invalidCount + "] sessions were stopped.";
            } else {
                msg = msg + "  No sessions were stopped.";
            }

            log.info(msg);
        }

    }

3.AbstractValidatingSessionManager.validate()方法
    
    3.1 AbstractValidatingSessionManager
        
        protected void validate(Session session, SessionKey key) throws InvalidSessionException {
            try {
                //(3)调用dpValidate()方法,如何session失效抛出InvalidSessionException异常
                this.doValidate(session);
            } catch (ExpiredSessionException var4) {
                this.onExpiration(session, var4, key);
                throw var4;
            } catch (InvalidSessionException var5) {
                //(4)捕获InvalidSessionExceptiony异常,调用onInvalidation()方法
                this.onInvalidation(session, var5, key);
                throw var5;
            }
        }
    
    3.2 AbstractValidatingSessionManager
        
        protected void doValidate(Session session) throws InvalidSessionException {
            if (session instanceof ValidatingSession) {
                //调用ValidatingSession.validate()方法
                ((ValidatingSession)session).validate();
            
            } else {
                String msg = "The " + this.getClass().getName() + " implementation only supports validating " + "Session implementations of the " + ValidatingSession.class.getName() + " interface.  " + "Please either implement this interface in your session implementation or override the " + AbstractValidatingSessionManager.class.getName() + ".doValidate(Session) method to perform validation.";
                throw new IllegalStateException(msg);
            }
        }
    
    3.3 SimpleSession
        
        public void validate() throws InvalidSessionException {
            if (this.isStopped()) {
                String msg = "Session with id [" + this.getId() + "] has been " + "explicitly stopped.  No further interaction under this session is " + "allowed.";
                throw new StoppedSessionException(msg);
            } else if (this.isTimedOut()) {
                this.expire();
                Date lastAccessTime = this.getLastAccessTime();
                long timeout = this.getTimeout();
                Serializable sessionId = this.getId();
                DateFormat df = DateFormat.getInstance();
                String msg = "Session with id [" + sessionId + "] has expired. " + "Last access time: " + df.format(lastAccessTime) + ".  Current time: " + df.format(new Date()) + ".  Session timeout is set to " + timeout / 1000L + " seconds (" + timeout / 60000L + " minutes)";
                if (log.isTraceEnabled()) {
                    log.trace(msg);
                }
                //抛出ExpiredSessionException异常(实现了InvalidSessionException)
                throw new ExpiredSessionException(msg);
            }
        }
    
4.AbstractValidatingSessionManager.onInvalidation()方法
    
    protected void onInvalidation(Session s, InvalidSessionException ise, SessionKey key) {
        if (ise instanceof ExpiredSessionException) {
            this.onExpiration(s, (ExpiredSessionException)ise, key);
        } else {
            log.trace("Session with id [{}] is invalid.", s.getId());

            try {
                //(5)调用onStop()方法
                this.onStop(s);
                //(6)调用notifyStop()方法
                this.notifyStop(s);
            } finally {
                //(7)最终调用afterStopped()方法
                this.afterStopped(s);
            }

        }
    }


##################################################################
###二、Shiro简单实现登录校验与权限验证的流程(SecurityManager)###
##################################################################

ApplicationCode-->  Subject  -->      SecurityManager  -->  Realm
                (The current user)    (manages all Subject) (access your sercurity data)

                
1.LoginController

    @RequestMapping(value = "/login",method = RequestMethod.POST)
    @ResponseBody
    public ResultVo<Map<String,Object>> doLogin(User user, HttpServletRequest request){


        Map<String,Object> map=new HashMap<>();

        if (StringUtils.isEmpty(user.getUsername())){
            return ResultVoUtil.failed("请输入用户名!");
        }
        if (StringUtils.isEmpty(user.getPassword())){
            return ResultVoUtil.failed("请输入密码!");
        }

        //使用Shiro进行登录校验 SecurityUtils.getSubject().login(token);
        try {
            //(1)获取认证对象
            Subject subject = SecurityUtils.getSubject();
            //(2)实例化Token对象
            UsernamePasswordToken token=new UsernamePasswordToken(user.getUsername(),user.getPassword());
            //(3)进行登录认证
            subject.login(token);(进入UserRealm的doGetAuthenticationInfo)
        }catch (Exception e){
        
            return ResultVoUtil.failed("账号密码有误!");
        }

        map.put("url",request.getContextPath()+"/index");
        return ResultVoUtil.success(map);
    }
    
    
2.UserRealm

    public class UserRealm extends AuthorizingRealm {

        @Autowired
        UserService userService;
        @Autowired
        RoleService roleService;
        @Autowired
        PermissionService permissionService;

        /**
         * 授权信息,用于进行权限认证
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            //(1) 获得签名, 可做进一步查询
            User user= (User) principalCollection.getPrimaryPrincipal();
            //(2)创建SimpleAuthenticationInfo对象
            SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
            //(3)查询角色、权限信息
            Set<String> roles = roleService.findRolesByUser(user);
            info.setRoles(roles);

            Set<String> permissions = permissionService.findPermissionsByUser(user);
            info.addStringPermissions(permissions);
            return info;
        }

        /**
         *  认证信息,主要针对用户登录,
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            //(1)获取登录的token
            UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
            //(2)获取username和password,调用登录
            String username=token.getUsername();
            String password=new String(token.getPassword());

            User user=new User();
            user.setUsername(username);
            user.setPassword(password);

            User login = userService.login(user);

            //(3)登录失败
            if (null==login){
                throw new AccountException("账号或密码不正确!");
            }
            if (user.getStatus()==0){
                throw new DisabledAccountException("帐号已经禁止登录!");
            }

            //(4)登录成功
            user.setUpdatetime(new Date());
            userService.updateUser(user);

            return new SimpleAuthenticationInfo(user,user.getPassword(),user.getUsername());
        }
    }

3.配置文件

    <!-- (二)SecurityManager -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm"/>
        <property name="sessionManager" ref="sessionManager"/>
        <property name="rememberMeManager" ref="rememberMeManager"/>
        <property name="cacheManager" ref="customShiroCacheManager"/>
    </bean>
    <!-- ShiroCacheManager -->    <!-- 用于缓存AuthenticationInfo -->
    <bean id="customShiroCacheManager" class="com.brillilab.ssmdemo.common.shiro.cache.impl.CustomShiroCacheManager">
        <property name="shiroCacheManager" ref="jedisShiroCacheManager"/>
    </bean>
    <!-- shiro 缓存实现,对ShiroCacheManager,我是采用redis的实现 -->
    <bean id="jedisShiroCacheManager" class="com.brillilab.ssmdemo.common.shiro.cache.impl.JedisShiroCacheManager">
        <property name="jedisManager" ref="jedisManager"/>
    </bean>

    <!-- 授权 认证 -->
    <bean id="userRealm" class="com.brillilab.ssmdemo.common.shiro.realms.UserRealm" >
        <property name="cacheManager" ref="customShiroCacheManager"/>
        <property name="cachingEnabled" value="false"/>
        <property name="authenticationCachingEnabled" value="true"/>
        <property name="authenticationCacheName" value="authenticationCache"/>
        <property name="authorizationCachingEnabled" value="true"/>
        <property name="authorizationCacheName" value="authorizationCache"/>
    </bean>

    
    
#############################################################
###三、Shiro简单实现登录拦截和权限拦截(使用自定义拦截器)###
#############################################################

(一)自定义拦截器的配置

    <!-- (五)shiro权限过滤器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value="/login" />
        <property name="successUrl" value="/index" />
        <property name="unauthorizedUrl" value="/login" />
        <!-- 过滤器映射 -->
        <property name="filterChainDefinitions" >
            <value>
                /common/** = anon
                /login = anon
                /index = anon
                /user/insert = login,permission
                /user/delete = login,permission
            </value>
        </property>
        <property name="filters">
            <util:map>
                <entry key="login" value-ref="login"></entry>
                <entry key="role" value-ref="role"></entry>
            </util:map>
        </property>
    </bean>
    <!-- 自定义拦截器 -->
    <bean id="login" class="com.brillilab.ssmdemo.common.shiro.filter.LoginFilter"/>
    <bean id="role" class="com.brillilab.ssmdemo.common.shiro.filter.RoleFilter"/>
    <bean id="permission" class="com.brillilab.ssmdemo.common.shiro.filter.PermissionFilter"/>
    
(一)登录拦截

1.LoginFilter

    public class LoginFilter extends AccessControlFilter {
        /**
         * 写如何能通过该拦截器的逻辑
         */
        @Override
        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object o) throws Exception {
            //(1)获取认证信息
            User token = (User)SecurityUtils.getSubject().getPrincipal();
            //(2)登录请求直接放行
            if(null != token || isLoginRequest(request, response)){
                return true;
            }

            //(3)非登录请求,重定向到登录页面
            ResultVo result = ResultVoUtil.failed("当前用户没有登录!");
            WebUtil.jsonOut(response,result);

            return false;
        }

        /**
         * isAccessAllowed返回值为fales时经过该方法
         */
        @Override
        protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
            //保存Request和Response 到登录后的链接
            saveRequestAndRedirectToLogin(request, response);
            return false;
        }
    }


(二)权限拦截

2.RoleFilter

    public class RoleFilter extends AccessControlFilter {
        /**
         * 写如何能通过该拦截器的逻辑
         */
        @Override
        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object value) throws Exception {
            //(1)获取认证实体
            Subject subject = getSubject(request, response);
            //(2)进行角色校验(角色为"1"能通过)
            if (subject.hasAllRoles(Arrays.asList("1"))){
                return true;
            }
            //(3)未通过角色校验重定向回登录页面
            ((HttpServletResponse)response).sendRedirect(request.getServletContext().getContextPath()+"/login");
            return false;
        }

        /**
         * isAccessAllowed返回值为fales时经过该方法
         */
        @Override
        protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
            //(3)未通过角色校验重定向回登录页面
            //((HttpServletResponse)response).sendRedirect(request.getServletContext().getContextPath()+"/login");
            Subject subject = getSubject(request, response);
            if (subject.getPrincipal()==null){
                //未登录重定向登录页面
                saveRequest(request);
                WebUtils.issueRedirect(request,response,((HttpServletRequest)request).getContextPath()+"/login");
            }else {
                //已登录重定向未授权错误页面
                WebUtils.issueRedirect(request,response,((HttpServletRequest)request).getContextPath()+"/error/unauthorizerror");
            }
            return false;
        }
    }

3.PermissionFilter

    public class PermissionFilter extends AccessControlFilter {
        
        /**
         * 写如何能通过该拦截器的逻辑
         */    
        @Override
        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object o) throws Exception {
            //(1)获取认证实体
            Subject subject = getSubject(request,response);
            //(2)进行权限校验
                //①获取请求url
            HttpServletRequest httpRequest=(HttpServletRequest)request;
            String url = httpRequest.getRequestURI();
            String contextPath = httpRequest.getContextPath();
            if (url!=null && url.startsWith(contextPath)){
                url = url.replaceFirst(contextPath,"");
            }
                //②权限校验
            if (subject.isPermitted(url)){
                return true;
            }
            return false;
        }

        /**
         * isAccessAllowed返回值为fales时经过该方法
         */
        @Override
        protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
            //(3)未通过权限校验的逻辑
            Subject subject = getSubject(request, response);
            if (subject.getPrincipal()==null){
                //未登录重定向登录页面
                saveRequest(request);
                WebUtils.issueRedirect(request,response,((HttpServletRequest)request).getContextPath()+"/login");
            }else {
                //已登录重定向未授权错误页面
                WebUtil.jsonOut(response,ResultVoUtil.failed("用户未被授权该操作"));
            }
            return false;
        }
    }


#############################################################
###四、Shiro页面内容的授权显示                            ###
#############################################################
1.<shiro:guest>标签中的类容在游客访问时显示
    
    <!-- shiro标签测试 -->
    <shiro:guest>
    <li class="nav-item">
        <a class="nav-link" href="/login">Login</a>
    </li
    </shiro:guest>
    
2.<shiro:hasRole name="1">标签中的内容在用户登录情况下,角色包含name属性值时显示
    
    <shiro:hasRole name="1">
    <li class="nav-item">
        <a class="nav-link" href="#">管理员</a>
    </li
    </shiro:hasRole>
    
3.<shiro:hasPermission name="/user/insert">标签中的类容在用户登录情况下,权限包含name属性值时显示
    
    <shiro:hasPermission name="/user/insert">
    <li class="nav-item">
        <a class="nav-link" href="#">能够添加用户</a>
    </li
    </shiro:hasPermission>
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页