美文网首页
Shiro简单使用

Shiro简单使用

作者: hutou | 来源:发表于2017-05-01 13:24 被阅读266次

    起步

    Shiro官方网站
    这是一个很简单的安全框架
    我们的目标是搭建一个无session的认证授权系统

    项目整合

    Maven配置文件

            <!-- shiro权限认证 -->
            <dependency>   
                <groupId>org.apache.shiro</groupId>  
                <artifactId>shiro-core</artifactId>  
                <version>1.2.3</version>  
            </dependency>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-ehcache</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-web</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.2.3</version>
            </dependency>   
    

    web.xml文件修改

        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                <!-- 增加了一个shiro的配置文件 -->
                classpath:hcm-shiro.xml
                classpath:hcm-context.xml
            </param-value>
        </context-param>
    
        <!-- shiro 安全过滤器 -->
        <filter>
            <filter-name>shiroFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            <async-supported>true</async-supported>
            <init-param>
                <param-name>targetFilterLifecycle</param-name>
                <param-value>true</param-value>
            </init-param>
            <init-param>
                <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->
                <!--filter比bean优先加载,若由spring管理则filter中注入的bean就为Null-->
                <param-name>transformWsdlLocations</param-name>
                <param-value>true</param-value>
            </init-param>        
        </filter>
    
        <filter-mapping>
            <filter-name>shiroFilter</filter-name>
            <url-pattern>/*</url-pattern>
            <dispatcher>REQUEST</dispatcher>
        </filter-mapping>
    

    shiro配置文件

        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:util="http://www.springframework.org/schema/util"
               xmlns:aop="http://www.springframework.org/schema/aop"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="
               http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
            <!-- Realm实现 -->
            <bean id="statelessRealm" class="com.yun.hcmserver.common.shiro.TokenRealm">
                <property name="cachingEnabled" value="false"/>
            </bean>
    
            <!-- Subject工厂 -->
            <bean id="subjectFactory" class="com.yun.hcmserver.common.shiro.StatelessDefaultSubjectFactory"/>
    
            <!-- 会话管理器 -->
            <bean id="sessionManager" class="org.apache.shiro.session.mgt.DefaultSessionManager">
                <property name="sessionValidationSchedulerEnabled" value="false"/>
            </bean>
    
            <!-- 安全管理器 -->
            <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
                <property name="realm" ref="statelessRealm"/>
                <property name="subjectDAO.sessionStorageEvaluator.sessionStorageEnabled" value="false"/>
                <property name="subjectFactory" ref="subjectFactory"/>
                <property name="sessionManager" ref="sessionManager"/>
            </bean>
    
            <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
            <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
                <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
                <property name="arguments" ref="securityManager"/>
            </bean>
    
            <bean id="statelessAuthcFilter" class="com.yun.hcmserver.common.shiro.StatelessAuthcFilter"/>
    
            <!-- Shiro的Web过滤器 -->
            <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
                <property name="securityManager" ref="securityManager"/>
                <property name="filters">
                    <util:map>
                        <entry key="statelessAuthc" value-ref="statelessAuthcFilter"/>
                    </util:map>
                </property>
                <property name="filterChainDefinitions">
                    <value>
                        /login=anon
                        /reg=anon 
                        /forget=anon
                        /logout=anon
                        /assets/**=anon
                        /resource/**=anon
                        
                        /web/org/**=statelessAuthc,roles[role1]
                        /web/user/**=statelessAuthc,roles[role2]
    
                        /**=statelessAuthc
                    </value>
                </property>
            </bean>
    
            <!-- Shiro生命周期处理器-->
            <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    
        </beans>
    

    代码编写

    Realm的实现 TokenRealm

    public class TokenRealm extends AuthorizingRealm {
        @Override
        public boolean supports(AuthenticationToken token) {
            //仅支持StatelessToken类型的Token
            return token instanceof StatelessToken;
        }
        
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            
            if (principals == null) {
                throw new AuthorizationException("用户身份不能为空!");
            }
            
            Long userId = (Long)getAvailablePrincipal(principals);
            
            //  根据用户名查找角色,请根据需求实现
            SimpleAuthorizationInfo authorizationInfo =  new SimpleAuthorizationInfo();
            //  设置权限角色
            authorizationInfo.addRoles(gerUserRole(userId));
            return authorizationInfo;
        }
        
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            StatelessToken statelessToken = (StatelessToken) token;
            
            String serverInfo = statelessToken.getToken();
            Long userId = checkToken(statelessToken.getToken(),statelessToken.getApp()); 
            
            // 密码信息与Token中的认证信息一致则通过身份认证
            return new SimpleAuthenticationInfo(
                    userId,     //  用户名
                    serverInfo, //  密码信息
                    getName());
        }
    
        private Collection<String> gerUserRole(Long userId){
            //  测试用角色       
            Collection<String> roleInfo = new HashSet<String>();
            roleInfo.add("role1");
            roleInfo.add("role2");
    
            return roleInfo;
        }
        
        public Long checkToken(String token,boolean isClient) {
            //  验证登录的Token是否正确
            if("jijdojiejae".equals(token)){
                return 233L;
            }else{
                return null;
            }       
        }
    }
    

    自定义的Token

    public class StatelessToken implements AuthenticationToken {
    
        private static final long serialVersionUID = 1L;
        
        private String token;
        private boolean isApp;
        
        public StatelessToken(String token,boolean isApp) {
            this.token = token;
            this.isApp = isApp;
        }
    
        public boolean getApp() {
            return isApp;
        }
    
        public void setApp(boolean isApp) {
            this.isApp = isApp;
        }
    
        public String getToken() {
            return token;
        }
    
        public void setToken(String token) {
            this.token = token;
        }
    
        @Override
        public Object getPrincipal() {
           return token;
        }
    
        @Override
        public Object getCredentials() {
            return token;
        }
    }
    

    Subject工厂类

    public class StatelessDefaultSubjectFactory extends DefaultWebSubjectFactory {
    
        @Override
        public Subject createSubject(SubjectContext context) {
            //不创建session
            context.setSessionCreationEnabled(false);
            return super.createSubject(context);
        }
    }
    

    无状态权限过滤器

    public class StatelessAuthcFilter extends AccessControlFilter {
    
        @Override
        protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
            return false;
        }
    
        @Override
        protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            
            String token = request.getParameter(ComConst.TOKEN_PARAM_NAME);
            boolean isApp = false;
            
            StatelessToken loginToken = new StatelessToken(token, isApp);
            
            try {
                //  委托给Realm进行登录
                getSubject(request, response).login(loginToken);
            } catch (Exception e) {
                //  登录失败的情况下
                if(isApp){
                    ReturnBean bean = new ReturnBean();
                    bean.setMessage("not login");
                    bean.setStatus(ReturnTypeEnum.Restart);
                    bean.setData("");
                    Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();  
                    response.getWriter().print(gson.toJson(bean));      
                }else{
                    response.sendRedirect(request.getContextPath() + "/login");
                }
                
                return false;
            }
            
            return true;
        }
    }
    

    相关文章

      网友评论

          本文标题:Shiro简单使用

          本文链接:https://www.haomeiwen.com/subject/qrftuttx.html