Springboot核心技术SpringBoot精选java学习springboot

SpringBoot与Shiro整合

2019-07-21  本文已影响23人  椰子奶糖

SpringBoot与Shiro整合

Shiro基本概念

Apache Shiro 体系结构

Apache Shiro 体系结构

关于Shiro的Quickstart

官方Quickstart:
http://shiro.apache.org/10-minute-tutorial.html


Springboot 整合Shiro

 package zstu.edu.springboot.shiro;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

/**
 * shiro的配置类
 * Created by CHEN on 2019/7/20.
 */
@Configuration
public class ShiroConfig {


    /**
     * 创建ShiroFilterFactoryBean
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);


        //添加shiro的内置过滤器
        /**
         * Shiro内置过滤器,可以实现权限相关的拦截器
         *      常用过滤器:
         *          anon:无需认证(登录)可以访问
         *          authc:必须认证才可以访问
         *          user:如果使用rememberMe的功能可以直接访问
         *          perms:该资源必须得到资源权限才可以访问
         *          role:该资源必须得到角色权限才可以访问
         */
        Map<String,String> filterMap = new LinkedHashMap<>();
//        filterMap.put("/add","authc");
//        filterMap.put("/update","authc");

        //可以这么写
        //这里应当注意顺序,上下换一下就算设置了anon还是会被拦截,
        //而且目前的顺序会先调用/testThymeleaf,然后再调用login,login还是调用了,只是因为权限是anon所以才没有彖传
        //testThymeleaf..........
        //login................

        filterMap.put("/testThymeleaf","anon");
        filterMap.put("/login","anon");

        //授权过滤器
        //当前授权拦截后shiro会自动跳转到未授权页面
        filterMap.put("/add","perms[user:add]");


        filterMap.put("/*","authc");

        //修改默认登陆界面
        shiroFilterFactoryBean.setLoginUrl("/tologin");

        //设置未授权提示页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);


        return shiroFilterFactoryBean;

    }


    /**
     * @Qualifier拿到容器中的UserRealm对象
     * 创建DefaultWebSecurityManager
     */
    @Bean(name="securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联一个Realm
        securityManager.setRealm(userRealm);

        return securityManager;
    }


    /**
     * 创建Realm
     *
     * @return
     */
    @Bean(name = "userRealm")
    public UserRealm getRealm() {
        return new UserRealm();
    }
}

package zstu.edu.springboot.shiro;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * 自定义Realm
 * Created by CHEN on 2019/7/20.
 */
public class UserRealm  extends AuthorizingRealm {

    /**
     * 执行授权逻辑
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行授权逻辑");

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //应当对接数据库,这里为了方便,直接写死
        info.addStringPermission("user:add");

        return info;
    }


    /**
     * 执行认证的逻辑
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行认证逻辑");

        //后续应当从数据库中获得,先写死
        String name = "123";
        String password = "123";

        //判断用户名

        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        if (!token.getUsername().equals(name)){
            //用户名不存在
            return null;
            //shiro底层会抛出UnKnownAccountException
        }

        return new SimpleAuthenticationInfo("",password,"");
    }
}

分析

@RequestMapping("/login")
    public String login(String name ,String password,Model model) {
        System.out.println("name="+name);
        /**
         * 使用Shiro编写认证操作
         */
        //1.获取Subject
        Subject subject = SecurityUtils.getSubject();

        //封装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(name,password);

        //执行登录方法
        try {
            subject.login(token);
            //登录成功

            //跳转到test.html
            return "redirect:/testThymeleaf";
        }catch (UnknownAccountException e ){
            model.addAttribute("msg","用户名不存在");
            System.out.println("UnknownAccountException....................");
            return "login";
        }catch (IncorrectCredentialsException e ){
            model.addAttribute("msg","密码错误");
            System.out.println("IncorrectCredentialsException.......................");
            return "login";
        }
    }

认证流程:

认证流程

授权流程:

授权流程

最后写一点认证拦截

    //这里应当注意顺序,上下换一下就算设置了anon还是会被拦截,
    //而且目前的顺序会先调用/testThymeleaf,然后再调用login,login还是调用了,只是因为权限是anon所以才没有彖传
    //testThymeleaf..........
    //login................

    filterMap.put("/testThymeleaf","anon");
    filterMap.put("/login","anon");

    filterMap.put("/*","authc");

    //所以个人认为避免全拦截的好,拦截的方统一目录下,在认证拦截的时候只需要拦截这个文件下所有文件的请求
上一篇下一篇

猜你喜欢

热点阅读