• 基于Spring Boot整合shiro的基本使用


    1.引入依赖

            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.5.3</version>
            </dependency>

    2.了解shiro的三大对象(转载至:https://blog.csdn.net/qq_41430393/article/details/87730198):

    1.Subject(主体)

    应用代码的直接交互对象就是Subject,也就是说Shiro对外的核心API就是Subject,Subject代表了当前“用户”,这个用户不是指具体的某一个人,可以说与当前应用交互的任何东西都是Subject,与Subject的所有交互都会委托给SecurityManager来执行,可以理解为Subject只是一个充当门面的,真正的幕后老大是SecurityManager,SecurityManager才是实际的执行者。

    2.SecurityManager(安全管理器)

    所有与安全有关的操作都会与SecurityManager进行交互,并且SecurityManager管理者所有的Subject,可以看出它才是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMvc中的dispatcherServlet(前端控制器)的角色。

    3.Realm

    Shiro从Realm获取安全数据(用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法,也需要从Realm获取用户的角色权限来判断用户是否能进行一系列操作。可以把Realm看作DataSource数据源.

    3.配置shiroConfig类以及shiroReaml类

    shiroConfig类(将三大对象联系起来,配置需要拦截的页面):

    @Configuration //交由spring管理
    public class shiroConfig {
        //自底向上创建,并绑定
    
        //ShiroFilterFactoryBean,第三步
        @Bean
        public ShiroFilterFactoryBean getFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //关联安全管理器
            bean.setSecurityManager(securityManager);
    
            //添加shiro的内置过滤器
            /*
                anon:无需认证就可以访问
                authc:必须认证才能访问 验证密码和用户
                user:必须拥有 记住我 功能才能用
                perms:拥有对某个资源的权限才能访问
                role:拥有某个角色权限才能访问
             */
            //使用map添加相应页面的过滤
            Map<String, String> filterMap=new LinkedHashMap<>();
    
            //因为是链式过滤,所以得先过滤范围小的
            //不仅需要登陆还得拥有权限才可访问
            //表示数据库中user表中的字段perm为user:update才表示有这个权限访问改路径
            filterMap.put("/user/update","perms[user:update]");
            filterMap.put("/user/add","perms[user:add]");
    
            //需要登陆即可访问的页面
            filterMap.put("/user/*","authc");
    
            //设置未登录时,进入需要权限的页面时,跳转的登陆页面
            bean.setLoginUrl("/toLogin");
    
            //设置权限不足时跳转的页面
            bean.setUnauthorizedUrl("/noAuth");
            
            bean.setFilterChainDefinitionMap(filterMap);
    
            return bean;
        }
    
        //DefaultWebSecurityManager,第二步
        @Bean(name = "securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("getRealm") shiroRealm shiroRealm){
            DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
            //关联realm
            securityManager.setRealm(shiroRealm);
            return securityManager;
        }
    
    
        //创建realm对象,第一步@Bean交由spring管理
        @Bean
        public shiroRealm getRealm(){
            return new shiroRealm();
        }
    
    }

    shiroReaml类(用于实现用户认证和授权的操作)

    //授权和认证都会经过此类
    public class shiroRealm extends AuthorizingRealm {
        @Autowired
        userService service;
    
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            Subject subject = SecurityUtils.getSubject();//获取当前用户
            user currentUser = (user) subject.getPrincipal();//从当前用户中取出Principal(认证时已存储了user)
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//是AuthorizationInfo的实现类
            info.addStringPermission(currentUser.getPerm());//根据数据库中的perm字段添加相应的权限
            return info;
        }
    
    
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
            user user = service.findByUsername(token.getUsername());
            //用户名校验,查看是否存在用户名
            if(user==null){
                return null;//返回null表示账号不存在,会抛出异常UnknownAccountException
            }
            //密码校验,shiro自带检验
            //若是密码错误会抛出异常IncorrectCredentialsException
            return new SimpleAuthenticationInfo(user,user.getPassword(),"");
            //第一个参数是principal作用是传递信息的,如认证完后可以将数据库中查询的user放进去,
            //供授权时,给相应的用户添加相应数据库中的权限
        }
    }

    4.配置Controller的实现

    @Controller
    public class myController {
    
        @RequestMapping({"/","/index"})
        public String index(){
            return "index";
        }
    
        @RequestMapping("/user/add")
        public String add(){
            return "user/add";
        }
    
        @RequestMapping("/user/update")
        public String update(){
            return "user/update";
        }
    
        @RequestMapping("/toLogin")
        public String toLogin(){
            return "login";
        }
    
        @RequestMapping("/login")
        public String login(String username, String password, Model model){
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(username,password);
            try {
                subject.login(token);// 该操作会将token转至手写的realm类中的doGetAuthenticationInfo方法中认证登陆
                return "index";
            }catch (UnknownAccountException e){//用户名不存在
                model.addAttribute("msg","用户名不存在");
                return "login";
            }catch (IncorrectCredentialsException e){//密码不存在
                model.addAttribute("msg","密码错误");
                return "login";
            }
    
        }
    
        @RequestMapping("/noAuth")
        @ResponseBody
        public String noAuth(){
            return "权限不足!";
        }
    
        @RequestMapping("/logout")
        @ResponseBody
        public String logout(){
            SecurityUtils.getSubject().logout();//注销
            return "注销成功!";
        }
    }

    5.shiro整合thymeleaf

    a.引入整合的依赖:

            <dependency>
                <groupId>com.github.theborakompanioni</groupId>
                <artifactId>thymeleaf-extras-shiro</artifactId>
                <version>2.0.0</version>
            </dependency>

    b.在shiroConfig类中添加ShiroDialect类

        @Bean
        public ShiroDialect getDialect(){
            return new ShiroDialect();
        }

    c.在前端页面引入thymeleaf整合shiro的命名空间

    <html lang="en" xmlns:th="http://www.thymeleaf.org"
          xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">

    d.将登陆成功的用户保存至shiro的session(与HttpSession不同)

        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
            user user = service.findByUsername(token.getUsername());
            //用户名校验,查看是否存在用户名
            if(user==null){
                return null;//返回null表示账号不存在,会抛出异常UnknownAccountException
            }
            //登陆成功将用户放进session
            Subject currentSubject = SecurityUtils.getSubject();
            currentSubject.getSession().setAttribute("loginUser",user);
            //密码校验,shiro自带检验
            //若是密码错误会抛出异常IncorrectCredentialsException
            return new SimpleAuthenticationInfo(user,user.getPassword(),"");
            //第一个参数是principal作用是传递信息的,如认证完后可以将数据库中查询的user放进去,
            //供授权时,给相应的用户添加相应数据库中的权限
        }

    e.前端页面的逻辑实现

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org"
          xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
    </head>
    <body>
    <h1>首页</h1>
    <hr>
    <div th:if="${session.loginUser==null}">
    <a th:href="@{/toLogin}">登陆</a>
    </div>
    
    <div th:if="${session.loginUser!=null}">
    <a th:href="@{/logout}">点我注销</a>
        <div th:text="当前用户为+':'+${session.loginUser.Username}"></div>
    </div>
    
    <div shiro:hasPermission="user:add">
    <a th:href="@{/user/add}">add</a>
    </div>
    
    <div shiro:hasPermission="user:update">
    <a th:href="@{/user/update}">update</a>
    </div>
    
    </body>
    </html>
  • 相关阅读:
    python数据类型--字符串
    Cannot open include file: 'afxcontrolbars.h': No such file or directory
    关于找不到tbb_debug.dll解决办法
    Android fill_parent、wrap_content和match_parent的区别
    多个摄像头同步工作【转】
    如何查找openCV函数源代码[转]
    Opencv 完美配置攻略 2014 (Win8.1 + Opencv 2.4.8 + VS 2013)[转]
    CvCaptureFromCam
    OpenCV与相机的关系[转]
    10亿以内和987654互质正整数的和[转自深圳-冒泡]
  • 原文地址:https://www.cnblogs.com/shouyaya/p/13454687.html
Copyright © 2020-2023  润新知