Apache Shiro 安全框架(4)-与web集成

要将shiro与web集成必须要添加shiro-spring依赖:


    org.apache.shiro
    shiro-spring
    1.4.0

配置shiro

import org.apache.shiro.mgt.DefaultSecurityManager;
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.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 结合spring,shiro完成web的认证和授权
 */
@Configuration
public class ShiroConfig {

    @Bean
    public DefaultSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(definedRealm());
        return securityManager;
    }

    @Bean
    public DefinedRealm definedRealm(){
        DefinedRealm realm = new DefinedRealm();
        return realm;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter(){
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager());
        shiroFilter.setLoginUrl("/login");//设置登录URL
        shiroFilter.setUnauthorizedUrl("/403");//设置未授权URL
        shiroFilter.setSuccessUrl("/index");//设置登录成功后跳转URL

        //设置拦截的路径
        Map filterChain = new LinkedHashMap<>();
        filterChain.put("/logout","logout");
        filterChain.put("/css/**","anon");
        filterChain.put("/fonts/**","anon");
        filterChain.put("/images/**","anon");
        filterChain.put("/js/**","anon");
        filterChain.put("/login","anon");
        filterChain.put("/list","roles[frame]");
        filterChain.put("/**","authc");//设置在最后,按照顺序判断,如果匹配则返回
        shiroFilter.setFilterChainDefinitionMap(filterChain);

        return shiroFilter;
    }
}

登录控制器:

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
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 LoginController {

    @RequestMapping(value = "/login",method = RequestMethod.GET)
    public String login(){
        System.out.println("首页登录");
        return "login";
    }

    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(String username,String password){
        System.out.println("开始验证登录信息,username " + username );
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","123");
        try {

            subject.login(token);
            return "index";
        }catch (Exception e){
            e.printStackTrace();
        }
        return "login";

    }

    @RequestMapping("/index")
    public String index(){
        System.out.println("登录成功");
        return "index";
    }

    @RequestMapping("/403")
    public String error(){
        System.out.println("请先登录");
        return "403";
    }
}

以上简单实现了shiro和web的集成。集合以上shiro配置代码和POST请求方式的login()方法,与上一节的登录控制器比较,发现其实我们只是将realm和securityManager的Bean交个spring容器来管理。

上一节登录控制器如下:

 DefaultSecurityManager securityManager = new DefaultSecurityManager();
        //设置realm
        securityManager.setRealm(definedRealm);
        //绑定securityManager到securityUtils
        SecurityUtils.setSecurityManager(securityManager);
        //创建登录实体
        Subject subject = SecurityUtils.getSubject();
        //创建登录token
        UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","01d7f40760960e7bd9443513f22ab9af");
        //登录
        subject.login(token);

并且再配置ShiroFilterFactoryBean。通过该类来配置我们loginUrl、UnauthorizedUrl、SuccessUrl,以及用户访问时需要认证和鉴权的URL。

配置URL的规则

配置URL通配符的规则:

  • ?、*、**,注意通配符匹配不包括目录分隔符“/”
  • ?:匹配一个字符,如 /admin? 将匹配 /admin1,但不匹配 /admin 或 /admin/;
  •  *:匹配零个或多个字符串,如 /admin* 将匹配 /admin、/admin123,但不匹配 /admin/1;
  • **:匹配路径中的零个或多个路径,如 /admin/** 将匹配 /admin/a 或 /admin/a/b

后面的选项只能在下面的 表格中选择:

首先是认证相关,当我们配置认证相关过滤器时,如果没有认证通过将会跳转到我们配置的loginUrl。常用authc过滤器

Apache Shiro 安全框架(4)-与web集成_第1张图片

其次是授权相关的,当我们配置如下过滤器,鉴权没通过是,将会跳转到配置的UnauthorizedUrl。一般很少使用,因为使用注解会更方便

Apache Shiro 安全框架(4)-与web集成_第2张图片

上面提到了注解做鉴权,下面来看看如何使用shiro的注解鉴权。

shiro中注解的使用

首先是启用shiro-spring的aop,在shiro配置类中增加如下配置:

 /**
     * Spring的一个bean,有advisor决定对那些类实现AOP代理
     * 配置通过注解完成权限和角色验证
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisor = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisor.setProxyTargetClass(true);
        return defaultAdvisor;
    }

    /**
     * shiro类的实现Advisor的类,开启shiro的注解支持
     * 内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor
     * 拦截@RequiredRoles,@RequiredPermission注解的方法
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager());
        return advisor;
    }

    /**
     * shiro生命周期处理器
     * @return
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

在loginController中增加如下接口:

   @RequiresRoles("admin")
    @RequestMapping("list")
    public String list(){
        return "list";
    }

当我们登录成功后,再去访问该接口时,如果当前登录用户没有该角色将会抛出org.apache.shiro.authz.AuthorizationException异常。

以上就是shiro和web的初步结合,下一节来探讨shiro中会话管理


你可能感兴趣的:(Java)