• SpringBoot整合Apache Shiro


    Subject 用户主体 (把操作交给SecurityManager)
    SecurityManager 安全管理器 (关联Realm)
    Realm   Shiro连接数据的桥梁

    引入maven依赖

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

    配置自定义Realm

    UserRealm.java
    package com.shiro;
    
    import com.entity.User;
    import com.service.UserService;
    import org.apache.shiro.SecurityUtils;
    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.session.Session;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 自定义realm
     */
    public class UserRealm extends AuthorizingRealm {
    
        @Autowired
        private UserService userService;
    
    
        /**
         * 执行授权逻辑
         *
         * @param principalCollection
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
            //给请求进行授权
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    
            //获取登录用户信息
            Subject subject = SecurityUtils.getSubject();
    
            //取出来的user与下方认证方法中new SimpleAuthenticationInfo(user, user.getPassword(), getName());的第一个存入的参数对应
            User user = (User) subject.getPrincipal();
    
    
            //这里为了做演示,实际开发中需要从数据库获取该用户的权限
            List permList = new ArrayList();
            permList.add("user:delete");
    
    
            //添加请求的授权集合
            info.addStringPermissions(permList);
    
    
            return null;
        }
    
    
        /**
         * 执行认证逻辑
         *
         * @param authenticationToken
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
    
            //查询用户名是否存在
            User user = userService.findByUserName(token.getUsername());
            if (user == null) {
                //用户不存在,shiro底层会抛出UnknownAccountException异常
                throw new UnknownAccountException();
            }
    
            if (!user.getEnable()) {
                throw new LockedAccountException();
            }
    
            //通过这个进行认证,并返回 实际使用中密码要进行加密  这里放入的第一个参数user和上面授权方法中subject.getPrincipal();这个取到的内容对应
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
    
            // 当验证都通过后,把用户信息放在session里
            Session session = SecurityUtils.getSubject().getSession();
            session.setAttribute("user", user);
    
            return simpleAuthenticationInfo;
        }
    }


    shiro配置类
    ShiroConfig.java
    package com.shiro;
    
    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;
    import java.util.Map;
    
    
    /**
     * shiro配置类
     */
    @Configuration
    public class ShiroConfig {
    
    
        /**
         * 创建shiroFilterFatoryBean
         */
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(){
    
            ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
    
            //设置安全管理器
            shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager());
    
            //添加shiro内置过滤器
            /**
             * shiro内置过滤器,可以实现权限相关的拦截器功能
             * 常用的过滤器
             *      anon:无需认证(登录)可以访问
             *      authc:必须认证才可以访问
             *      user:如果使用rememberMe的功能可以直接访问
             *      perms:该资源必须得到资源权限才可以访问
             *      role:该资源必须得到角色权限才可以访问
             *
             */
            Map<String,String> filterMap=new LinkedHashMap<>();
    
            filterMap.put("/back/*","authc");
    
            //放行登录页面和登录提交请求
            filterMap.put("/login","anon");
            filterMap.put("/toLogin","anon");
    
            /**
             * 授权过滤器,表示用户执行 “/delete” 操作需要有 “user:delete” 的授权
             * 当前授权拦截后,shiro会自动跳转到未授权页面
             */
            filterMap.put("/delete","perms[user:delete]");
    
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
    
            //设置登录页面的请求链接
            shiroFilterFactoryBean.setLoginUrl("/toLogin");
    
            //设置未授权时的跳转链接
            shiroFilterFactoryBean.setUnauthorizedUrl("/toUnauthorizedUrl");
    
            return shiroFilterFactoryBean;
        }
    
    
        /**
         * 创建DefaultWebSecurityManager
         */
        @Bean
        public DefaultWebSecurityManager getDefaultWebSecurityManager(){
            DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
    
            //关联realm
            securityManager.setRealm(getRealm());
            return securityManager;
        }
    
        /**
         * 创建Realm
         */
        @Bean
        public UserRealm getRealm(){
            return new UserRealm();
        }
    
    
    
    
    }

    配置规则详细说明

    // 将需要配置的地址放入map中,规则如下:
    /**
    anon:例子/admins/**=anon 没有参数,表示可以匿名使用。
    
    authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数
    
    roles(角色):例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,
    并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],
    每个参数通过才算通过,相当于hasAllRoles()方法。
    
    perms(权限):例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,
    并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],
    当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
    
    rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,
    其中method为post,get,delete等。
    
    port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到
    schemal://serverName:8081?queryString,其中schmal是协议http或https等,
    serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。
    
    authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证
    
    ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https
    
    user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
    */
    // 详情参考shiro.web.filter源码

    控制器类,登录 退出方法

    LoginController.java
    package com.controller;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.LockedAccountException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.session.Session;
    import org.apache.shiro.subject.Subject;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class LoginController {
    
    
        /**
         * 登录请求方法
         *
         * @param username 用户名
         * @param password 密码
         * @return
         */
        @PostMapping(value = "/login")
        public String loginPost(String username, String password) {
    
            /**
             * 使用Shiro进行认证操作
             */
            //获取Subject
            Subject subject = SecurityUtils.getSubject();
    
            //封装用户数据
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    
            //是否记住我操作,这里我默认设置记住我
            token.setRememberMe(true);
    
    
            //执行登录方法
            try {
                subject.login(token);
    
                //登录成功操作
    
            } catch (UnknownAccountException e) {
                //用户不存在
                e.printStackTrace();
    
    
            } catch (IncorrectCredentialsException e) {
                //用户名密码错误
                e.printStackTrace();
    
    
            } catch (LockedAccountException e) {
                e.printStackTrace();
                //账号被禁用
            }
    
            return null;
        }
    
    
        /**
         * 登出
         *
         * @return
         */
        @RequestMapping("/logout")
        public String logout() {
            Subject subject = SecurityUtils.getSubject();
            subject.logout();
            Session session = subject.getSession();
            //情况session中的用户信息
            session.removeAttribute("user");
    
            //返回登录页
            return "login";
        }
    
    
    }



  • 相关阅读:
    防止浏览器记住用户名及密码的简单实用方法
    vb.net如何发送含双引号的字符串。转义双引号
    武神坛任务超详细解说。刷战神任务
    Asp.Net文件和文件夹操作大全
    LINQ 中的 select
    经典.net常用面试题目基础
    福建厦门联通DNS
    jQuery 遍历函数 each
    为什么 内燃机 要 先压缩空气 才能有效的将 热能 转化为 动能 ?
    【哈哈】 这个题能让官科吵几千楼我也是没想到的
  • 原文地址:https://www.cnblogs.com/pxblog/p/12943705.html
Copyright © 2020-2023  润新知