zoukankan      html  css  js  c++  java
  • Apache Shiro 集成Spring(二)

    1、依赖:

            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-core</artifactId>
                <version>1.4.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.4.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-web</artifactId>
                <version>1.4.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.9</version>
            </dependency>
    

    2、自定义Realm:

    package com.example.demo_mg.realm;
    
    import org.apache.commons.collections.map.HashedMap;
    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.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.crypto.hash.Md5Hash;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.util.ByteSource;
    
    import java.util.*;
    
    public class TestRealm extends AuthorizingRealm {
        //模拟users、user_roles、roles_permissions三张表的查询,实际应用需要查询数据库或缓存
        Map<String, String> users = new HashMap<>();
        Map<String, Set<String>> user_roles = new HashedMap();
        Map<String, Set<String>> roles_permissions = new HashedMap();
    //    String salt = UUID.randomUUID().toString().replaceAll("-","");
    
        {
            //不加盐(与认证对应)
            users.put("wzs", new Md5Hash("123456",null, 2).toString());
            //加盐
    //        users.put("wzs", new Md5Hash("123456",salt, 2).toString());
            user_roles.put("wzs", new HashSet<>(Arrays.asList("admin", "test")));
            roles_permissions.put("admin", new HashSet<>(Arrays.asList("user:delete", "user:update")));
            super.setName("TestRealm"); //设置Realm名称,可选
        }
    
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            //从认证信息获取用户名
            String username = (String)principalCollection.getPrimaryPrincipal();
            //从数据库或缓存中获取角色、权限数据
            Set<String> roles = user_roles.get(username);
            Set<String> permissions = new HashSet<>();
            for (String role : roles) {
                Set<String> set;
                if((set = roles_permissions.get(role)) != null) {
                    permissions.addAll(set);
                }
            }
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            simpleAuthorizationInfo.setRoles(roles);
            simpleAuthorizationInfo.setStringPermissions(permissions);
            return simpleAuthorizationInfo;
        }
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            //从主题传过来的认证信息中,获得用户名
            String username = (String)authenticationToken.getPrincipal();
            //通过用户名从数据库中获取凭证
            String password = users.get(username);
            if(password != null) {
                //不加盐
    //            return new SimpleAuthenticationInfo(username, password, super.getName());
                //加盐
                SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, super.getName());
    //            simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(salt));
                return simpleAuthenticationInfo;
            }
            return null;
        }
    }
    

    3、配置:

    package com.example.demo_mg.config;
    
    import com.example.demo_mg.realm.TestRealm;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.spring.LifecycleBeanPostProcessor;
    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.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.LinkedHashMap;
    
    @Configuration
    public class ShiroConfiguration {
        @Bean
        public HashedCredentialsMatcher getCredentialsMatcher() {
            HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
            credentialsMatcher.setHashAlgorithmName("md5");
            credentialsMatcher.setHashIterations(2);
            return credentialsMatcher;
        }
    
        @Bean
        public TestRealm getRealm(HashedCredentialsMatcher credentialsMatcher) {
            TestRealm testRealm = new TestRealm();
            testRealm.setCredentialsMatcher(credentialsMatcher);
            return testRealm;
        }
    
        @Bean
        public DefaultWebSecurityManager getDefaultWebSecurityManager(TestRealm testRealm) {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(testRealm);
            return  securityManager;
        }
    
        @Bean
        public ShiroFilterFactoryBean getShiroFilter(SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            shiroFilterFactoryBean.setLoginUrl("login.html");
            shiroFilterFactoryBean.setUnauthorizedUrl("403.html");
            LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
            filterChainDefinitionMap.put("/login.html", "anon");
            filterChainDefinitionMap.put("/login", "anon");
            filterChainDefinitionMap.put("/*", "authc");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return shiroFilterFactoryBean;
        }
    
        /**
         * 注解式授权2个bean
         * @return
         */
        //Shiro生命周期处理器
        @Bean
        public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
    
        @Bean
        public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    }
    

    4、实体:

    package com.example.demo_mg.entity;
    
    public class User {
        private String username;
        private String password;
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    }
    

    5、控制器:

    package com.example.demo_mg.controller;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.authz.annotation.RequiresPermissions;
    import org.apache.shiro.authz.annotation.RequiresRoles;
    import org.apache.shiro.subject.Subject;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    @Controller
    public class LoginContrller {
        @RequestMapping(value = "/login",method = RequestMethod.GET)
        public String loginUser(String username, String password) {
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
            Subject subject = SecurityUtils.getSubject();
            try {
                subject.login(usernamePasswordToken);   //完成登录
                //更新用户登录时间,也可以在ShiroRealm里面做
                return "index";
            } catch(Exception e) {
                return "login";//返回登录页面
            }
        }
    
        @RequestMapping("/logout")
        public String logout() {
            Subject subject = SecurityUtils.getSubject();
            subject.logout();
            return "login";
        }
    
        @RequestMapping("/test")
        public void test() {
            System.out.println("test");
        }
    
        @RequiresRoles("admin")
        @RequestMapping("/role")
        public void role() {
            System.out.println("role");
        }
    
        @RequiresPermissions("user:delete1")
        @RequestMapping("/permission")
        public void permission() {
            System.out.println("permission");
        }
    }
    

    6、自定义过滤器,授权继承AuthorizationFilter,认证继承AuthenticatinFilter,可以阅读其源码。
    Shiro提供的认证过滤器包括anon,authBasic,authc,user,logout,授权过滤器包括perms,roles,ssl,port,举例perms["user:delete","user:update"],roles["admin","user"],方括号内的角色或权限需要同时满足,否则跳到unauthorizadUrl,ssl是https过滤器。
    自定义过滤器例子,角色满足一个即可:

    package com.example.demo_mg.filter;
    
    import org.apache.shiro.subject.Subject;
    import org.apache.shiro.web.filter.authz.AuthorizationFilter;
    
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    public class RoleOrFilter extends AuthorizationFilter {
        @Override
        protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
            Subject subject = getSubject(servletRequest, servletResponse);
            String[] roles = (String[])o;
            if(roles == null || roles.length == 0) {
                return true;
            }
            for (String role : roles) {
                if(subject.hasRole(role)) {
                    return true;
                }
            }
            return false;
        }
    }
    

    拿到subject,o是配置的过滤器方括号里面的数组,return true;表示通过过滤器。

    配置类修改使自定义过滤器生效:

        @Bean
        public ShiroFilterFactoryBean getShiroFilter(SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            shiroFilterFactoryBean.setLoginUrl("login.html");
            shiroFilterFactoryBean.setUnauthorizedUrl("403.html");
            LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
            filterChainDefinitionMap.put("/login.html", "anon");
            filterChainDefinitionMap.put("/login", "anon");
            filterChainDefinitionMap.put("/filter", "roleOr[admin,user]");
            filterChainDefinitionMap.put("/*", "authc");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            //自定义拦截器
            LinkedHashMap<String, Filter> filters = new LinkedHashMap<>();
            filters.put("roleOr", getRoleOrFilter());
            shiroFilterFactoryBean.setFilters(filters);
            return shiroFilterFactoryBean;
        }
    
        @Bean
        public RoleOrFilter getRoleOrFilter() {
            RoleOrFilter roleOrFilter = new RoleOrFilter();
            return roleOrFilter;
        }
    

    测试:

        @RequestMapping("/filter")
        public void filter() {
            System.out.println("filter");
        }
    
  • 相关阅读:
    【体验】在Adobe After Effects CC 2018中使用脚本创建窗口
    flask中错误使用flask.redirect('/path')导致的框架奇怪错误
    01-复杂度2 Maximum Subsequence Sum
    01-复杂度1 最大子列和问题
    02-线性结构1 两个有序链表序列的合并
    bfs—迷宫问题—poj3984
    bfs—Dungeon Master—poj2251
    bfs—Catch That Cow—poj3278
    GPTL—练习集—006树的遍历
    DB2存储过程——参数详解
  • 原文地址:https://www.cnblogs.com/kibana/p/11108025.html
Copyright © 2011-2022 走看看