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");
    }
posted @ 2019-06-29 21:54  发挥哥  阅读(375)  评论(0编辑  收藏  举报