shiro-入门,快速与springmvc整合,全注解,最简单让项目运行起来

来源:互联网 发布:在线域名生成器短链接 编辑:程序博客网 时间:2024/05/29 18:09

笔记:springboot、springmvc全注解入门整合shiro

功能介绍

2015-11-19注 :最近看了架构探险中对shiro的讲解,下面这篇文章,在使用的方式上是正确的,有一些配置和使用至于是为什么,则需要你们自己去看架构探险章节的说明了,时隔一年来看这篇文章还是觉得很有价值,在当时也只会用使用能满足自己的要求。
本文的认证方法处理有误,正确的应该是:login提交用户表单提交的用户名和密码,doGetAuthenticationInfo认证方法里面放置正确的用户名和密码,让框架去匹配是否通过认证,以抛出异常的方式进行通知调用处没有通过认证,session中不会存放该用户的信息。

该示例:大概功能如下:
由于角色可以自由创建,拥有权限分配的功能的帐号,可以把自身的权限分配给创建的角色。所以本人只想到了,使用请求地址来控制每一个权限。
整合开始:

1.添加shiroFilter过滤器

在能替代web.xml的配置类中添加过滤器

/** * 用注解方式,类里面配置,完全取代 web.xml中的配置 * @author admin */@Order(1) //第一启动顺序@HandlesTypes(WebApplicationInitializer.class) //可能是标识这个是一个web上下文初始化的类(在springboot中该类需要在WebMvcConfigurerAdapter(可自定义继承该类)中加载调用)public class WebXml implements ServletContextInitializer {    Logger logger = LoggerFactory.getLogger(getClass());    @Override    public void onStartup(ServletContext servletContext) throws ServletException {        logger.info("加载shiro过滤器,与spring集成");        /**         * 找名字为shiroFilter(filter-name)的bean 并把所有Filter的操作委托给它。然后将ShiroFilter         * 配置到spring容器即可         */        Dynamic shiroFilter = servletContext.addFilter("shiroFilter", DelegatingFilterProxy.class);        shiroFilter.setInitParameter("argetFilterLifecycl", "true");        shiroFilter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");        shiroFilter.setAsyncSupported(true);    }}

2.配置WebMvcConfigurer

下面的类中有点多,但是指需要添加与shiro先关的几个bean就成了。
之前的是在项目中配置好的

public class WebConfig extends WebMvcConfigurerAdapter {    Logger logger = LoggerFactory.getLogger(getClass());    @Bean    public ServletContextInitializer getMyFilter() {        logger.info("注册web.xml中对应的配置都可以在这里类里面编写-----------");        return new WebXml();    }    /**     * 添加全局异常处理器 1:这里好像是不用屏蔽 springmvc自动注册的全局异常处理器 2:编写自定义处理器 实现     * HandlerExceptionResolver 3:在这里加载     * */    @Bean    public HandlerExceptionResolver getHandlerExceptionResolver() {        logger.info("加载自定义异常处理器");        return new ExceptionResolverCustom();    }    @Override    public void addInterceptors(InterceptorRegistry registry) {        logger.info("自定义拦截器在这里增加");        registry.addInterceptor(new LoginInterceptor());        super.addInterceptors(registry);    }    /*     * @Bean public InternalResourceViewResolver     * getInternalResourceViewResolver() { logger.info("加载视图解析器,配置springmvc的视图解析器,一般用于jsp开发?");     * InternalResourceViewResolver resolver = new     * InternalResourceViewResolver(); resolver.setSuffix(".html"); return     * resolver; }     */    @Bean    public EmbeddedServletContainerCustomizer containerCustomizer() {        logger.info("加载错误页面相关处理,spring boot中可以对根据对应的状态码,比如404,等添加指定的页面");        return new MyCustomizer();    }//会话ID生成器     @Bean    public SessionIdGenerator sessionIdGenerator() {        JavaUuidSessionIdGenerator jusg = new JavaUuidSessionIdGenerator();        return jusg;    }//    <!-- 会话DAO,用来方便的获得 当前用户的session,也就是说,在任何一个普通类里面都可以使用Subject subject = SecurityUtils.getSubject();  Session session = subject.getSession();   这个代码来获取当前用户的session -->    @Bean    public EnterpriseCacheSessionDAO sessionDao() {        EnterpriseCacheSessionDAO ecd = new EnterpriseCacheSessionDAO();        ecd.setSessionIdGenerator(this.sessionIdGenerator());        ecd.setCacheManager(this.shiroCacheManager());        return ecd;    }    private EhCacheManager ec  = null;    //缓存,这个缓存,没有集成成功。    @Bean    public EhCacheManager shiroCacheManager() {        if(ec == null) {            ec = new EhCacheManager();            ec.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");        }        return ec;    }    //会话管理器    @Bean    public SessionManager sessionManager() {        DefaultWebSessionManager dwsm = new DefaultWebSessionManager();        dwsm.setGlobalSessionTimeout(1800000); // 超时        dwsm.setDeleteInvalidSessions(true);//      dwsm.setSessionValidationSchedulerEnabled(true);//      dwsm.setSessionValidationScheduler(this.);//      dwsm.setCacheManager(this.shiroCacheManager());        dwsm.setSessionDAO(this.sessionDao());        return dwsm;    }    //安全管理器    @Bean    public SecurityManager securityManager() {        UserRealm singleRealm = new UserRealm();        singleRealm.setAuthorizationCachingEnabled(true);        DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager(singleRealm); //加载自定义realm域        dwsm.setSessionManager(this.sessionManager());        return dwsm;    }    //<!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->    @Bean    public MethodInvokingFactoryBean methodInvokingFactoryBean() {        MethodInvokingFactoryBean mifb = new MethodInvokingFactoryBean();        mifb.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");        mifb.setArguments(new Object[] {this.securityManager()});        return mifb;    }    //web过滤器    @Bean(name="shiroFilter")    public ShiroFilterFactoryBean shiroFilterFactoryBean () {        ShiroFilterFactoryBean sffb = new ShiroFilterFactoryBean();        sffb.setSecurityManager(this.securityManager());        sffb.setLoginUrl("/login.html");//设置登录页面        sffb.setUnauthorizedUrl("/unAuthc.html"); //未授权跳转的页面        Map<String, Filter> filters = new HashMap<>();        filters.put("sysUser", new SysUserFilter()); //自定义过滤器,我是用它来拦截自定义的权限监测调用        sffb.setFilters(filters);        //设置对应的url对应的过滤链        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();        filterChainDefinitionMap.put("/login.html", "anon");        filterChainDefinitionMap.put("/system/login/login", "anon");        filterChainDefinitionMap.put("/system/login/logOut", "anon");        filterChainDefinitionMap.put("/errorCustom.html", "anon");        filterChainDefinitionMap.put("/unAuthc.html", "anon");        filterChainDefinitionMap.put("/views/app.js", "anon");        filterChainDefinitionMap.put("/js/**", "anon");        filterChainDefinitionMap.put("/", "anon");        filterChainDefinitionMap.put("/images/**", "anon");        filterChainDefinitionMap.put("/imag/**", "anon");        filterChainDefinitionMap.put("/wxMessagePic/*", "anon");        filterChainDefinitionMap.put("/css/**", "anon");        filterChainDefinitionMap.put("/**", "sysUser");//可以看到对于一些公共的地址我进行了放行,对于/**使用了自定义的过滤器进行处理,意思就是说:除了以上放行的地址,其他的地址都会被调用自定义的过滤器方法中              sffb.setFilterChainDefinitionMap(filterChainDefinitionMap);        return sffb;    }    //shiro 生命周期处理器    @Bean    public LifecycleBeanPostProcessor LifecycleBeanPostProcessor() {        return new LifecycleBeanPostProcessor();    }}

3.编写自定义UserRealm

获取spring容器思路:12

import org.apache.shiro.realm.AuthorizingRealm;public class UserRealm extends AuthorizingRealm {    /**     * 获取授权信息,用户所拥有的角色和权限     */    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {         //这里能得到这个参数,就是在下面的doGetAuthenticationInfo返回的用户验证信息。(这个是单realm的实现,直接调用这个方法,就能获得自定义的对象了)        ShiroPrincipal shiroPrincipal = (ShiroPrincipal) principals.getPrimaryPrincipal();        Set<String> psIds = null;        if (shiroPrincipal.isAuthorized()) {            psIds = shiroPrincipal.getAuthorities();        } else {            ISecurityService iss = Config.webApplicationContext.getBean(ISecurityService.class);            try {                psIds = iss.findByUsername(shiroPrincipal.getUsername());                shiroPrincipal.setAuthorized(true);            } catch (Exception e) {                e.printStackTrace();            }        }        SimpleAuthorizationInfo si = new SimpleAuthorizationInfo();        si.setStringPermissions(psIds); // setRoles 暂时只实现权限判断        return si;    }    /**     * 获取身份验证相关信     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {        //这个token,是在登录方法里面,调用login方法,把用户名和密码传递过来的        //Subject subject = SecurityUtils.getSubject();        //subject.login(new UsernamePasswordToken(systemVo.getUsername(), systemVo.getPassword()));        String username = (String) token.getPrincipal(); // 得到用户名        String password = new String((char[]) token.getCredentials()); // 得到密码        // 如果身份认证验证成功,返回一个AuthenticationInfo实现        // 这里处理的流程:暂时是,先通过了系统的自定义流程之后,再调用shiro的login功能,跳转到这里,所以        // 就不用去获取用户等数据了。直接返回对象:简单的对象实体 new SimpleAuthenticationInfo(username,        // password, getName());        // 第一个参数,可以在授权方法中获取到        ShiroPrincipal principal = new ShiroPrincipal(username);        return new SimpleAuthenticationInfo(principal, password, this.getName());    }}

4.编写自定义过滤器

import org.apache.shiro.SecurityUtils;import org.apache.shiro.subject.Subject;import org.apache.shiro.web.filter.PathMatchingFilter;public class SysUserFilter extends PathMatchingFilter {    @Override    protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {        HttpServletRequest req = (HttpServletRequest) request;           HttpServletResponse res = (HttpServletResponse) response;           String url = req.getRequestURI();// 用户请求的地址        Subject subject = SecurityUtils.getSubject();        String username = (String)subject.getPrincipal();        if("superadmin".equals(username)) { //系统超级管理员放行            return true;        }        Integer rulKey = this.matchingURL(url);         if(subject.isPermitted(rulKey+"")) { //如果有权限。则放行            return true;        }else {            String method = req.getMethod();            String header = req.getHeader("Accept");            if(header.startsWith("application/json")) {             JSONObject responseJSONObject = new JSONObject();               responseJSONObject.put("0", "你没有该权限");             res.setContentType("application/json; charset=utf-8");               res.setCharacterEncoding("UTF-8");               PrintWriter out = null;               out = res.getWriter();               out.append(responseJSONObject.toString());              }        }        res.sendRedirect("/unAuthc.html");        return false;    }    /**     *      * @Title: matchingURL      * @Description:根据当前请求地址获取标准的公共权限地址,只要是正常的访问。就应该能和公共权限中 一一对应查找到      * @param currentUrl      * @return Integer 获取到后,返回该公共地址的权限id,返回null,则表示请求的资源在公共权限库中没有找到(待定义处理)     * @version V0.1       * @createDate 2015年3月18日 下午4:00:40      * @updateDate 2015年3月18日 下午4:00:40     */    private Integer matchingURL(String currentUrl) {        Map<Integer, String> authUrls = StaticCache.authUrls;        for (Map.Entry<Integer, String> url : authUrls.entrySet()) {            if(currentUrl.contains(url.getValue())) { //匹配上                return url.getKey();            }        }        return null;    }}

5.总结

用一张图来表示,shiro大概的入门调用流程,这个是自己花了一天时间理解的。也不知道对不对。反正就先这样用着先。
shiro调用简单流程

总结步骤:
1.添加shiro过滤器入口(一定要保证白过滤器在其他过滤器之前,至少在配置清单中在最前面)
2:配置安全管理器,设置自定义realm
3:配置web过滤器(也就是定义shiroFilter,定义的入口会搜寻该对象),设置权限,设置自定义过滤器拦截权限处理


  1. 我是专门做了一个监听器,在监听器中利用servletcontext来获取到spring的容易,然后存入一个工具类中的静态常量中。也就是说这样操作之后,在一个普通的java类中也可以获得spring容器 ↩
  2. 用一个工具类实现spring的接口,然后用spring容器初始化该工具类,就能获取容器了 ↩
0 0
原创粉丝点击