zoukankan      html  css  js  c++  java
  • Spring Boot 整合Shiro 最新 最全面(Mybatis版本)

    1: 依赖

    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
            <dependency>
                <groupId>com.github.theborakompanioni</groupId>
                <artifactId>thymeleaf-extras-shiro</artifactId>
                <version>${thymeleaf-shiro.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.2</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
           <dependency>
               <groupId>org.apache.shiro</groupId>
               <artifactId>shiro-spring</artifactId>
               <version>1.5.1</version>
          </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.xmlunit</groupId>
                <artifactId>xmlunit-core</artifactId>
            </dependency>
        </dependencies>

    2: application.xml配置

    #server.servlet.context-path=/hello
    ##端口号
    server.port=8888
    
    ##检查 mybatis 配置是否存在,一般命名为 mybatis-config.xml
    mybatis.check-config-location =true
    ##配置文件位置 Resource下mybaits文件夹
    mybatis.config-location=classpath:mybatis/mybatis-config.xml
    ## mapper xml 文件地址  Resource下mapper文件夹
    mybatis.mapper-locations=classpath*:mapper/*Mapper.xml
    ##日志级别 com.yang.dao 为包名
    #logging.level.com.dgw.springbootandshiro.dao=debug
    ##数据库url
    spring.datasource.url=jdbc:mysql://localhost/rbac?userSSL=true&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT
    ##数据库用户名
    spring.datasource.username=root
    ##数据库密码
    spring.datasource.password=root
    ##数据库驱动
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    
    
    spring.thymeleaf.check-template-location=true
    spring.thymeleaf.encoding=UTF-8
    spring.thymeleaf.prefix=classpath:/templates/
    spring.thymeleaf.suffix=.html
    # 建议在开发时关闭缓存,不然没法看到实时页面
    spring.thymeleaf.cache=false
    ##去除thymeleaf的html严格校验
    spring.thymeleaf.mode=HTML
    
    spring.main.allow-bean-definition-overriding=true
    
    #debug=true
    #简单设置一下日志等级
    logging.level.web=info
    logging.level.root=info

    3: Mybatis 配置:

      目录结构如下:

     image

    Mybatis 配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD SQL Map Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <typeAliases>
            <typeAlias alias="Integer" type="java.lang.Integer" />
            <typeAlias alias="Long" type="java.lang.Long" />
            <typeAlias alias="HashMap" type="java.util.HashMap" />
            <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
            <typeAlias alias="ArrayList" type="java.util.ArrayList" />
            <typeAlias alias="LinkedList" type="java.util.LinkedList" />
            <typeAlias alias="user" type="com.dgw.springbootandshiro.bean.User"/>
        </typeAliases>
    </configuration>
     

    实体类

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private Integer id;
        private String username;
        private String password;
        private String salt;
    }
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Role {
        private Integer id;
        private String roleName;
        private Date createTime;
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Permission {
        private Integer id;
        private String permissionName;
        private Date createTime;
    }


    dao接口: 部分 其余扎着框框画鸭蛋

    @Mapper
    public interface UserMapper {
        User queryUserByUsername(@Param("username") String username);
        Integer insertUser(User user);
    }

    services实现:

    @Service
    public class UserServiceImpl implements UserService {
    
        @Autowired
        private UserMapper userDAO;
    
        @Override
        @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = SQLException.class)
        public User queryUserByUsername(String username) {
            return userDAO.queryUserByUsername(username);
        }
    
        @Override
        public Integer insertUser(User user) {
            // 加密
            String salt = UUID.randomUUID().toString();
            String s = new Sha256Hash(user.getPassword(), salt, MyConstant.INTERCOUNT).toBase64();
            // 设置密文
            user.setPassword(s);
            // 设置盐
            user.setSalt(salt);
            return userDAO.insertUser(user);
        }
    }


    3: Shiro配置

    Realm配置i

    public class ShiroRealm extends AuthorizingRealm {
    
        @Autowired
        private UserService userService;
        @Autowired
        private RoleService roleService;
        @Autowired
        private PermissionService permissionService;
        // 授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            String  username  = (String)principalCollection.getPrimaryPrincipal();
            // 查询当前用户的权限信息
            Set<String> roles = roleService.queryAllRolenameByUsername(username);
            Set<String> perms = permissionService.queryAllPermissionByUsername(username);
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(roles);
            simpleAuthorizationInfo.setStringPermissions(perms);
    
            return simpleAuthorizationInfo;
        }
    
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            String usernmae = (String) authenticationToken.getPrincipal();
            User user = userService.queryUserByUsername(usernmae);
            if (user == null) {
                return null;
            }
            //这里会去校验密码是否正确
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    user.getUsername(),
                    user.getPassword(),
                    ByteSource.Util.bytes(user.getSalt()),
                    getName()
            );
            return authenticationInfo;
        }
    }
     

    Shiroconfig 配置


    @Configuration
    public class ShiroConfig {
    
        private final Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Bean("shiroFilterFactoryBean")
        public ShiroFilterFactoryBean shirFilter(@Qualifier("securityManager") SecurityManager securityManager) {
            logger.info("启动shiroFilter--时间是:" + new Date());
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            //shiro拦截器
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
            //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
            //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->
            Map<String, Filter> filterMap=new LinkedHashMap<String, Filter>();
            filterMap.put("MyRememberFilter", new MyRememberFilter());
    
            shiroFilterFactoryBean.setFilters(filterMap);
    
            // 如果不设置默认会自动寻找Web工程根目录下的"/login"页面,即本文使用的login.html
            shiroFilterFactoryBean.setLoginUrl("/login");
            // 登录成功后要跳转的链接
            shiroFilterFactoryBean.setSuccessUrl("/main");
            //错误页面,认证不通过跳转
            shiroFilterFactoryBean.setUnauthorizedUrl("/error");
            //未授权界面
            shiroFilterFactoryBean.setUnauthorizedUrl("/403");
    
    
            // 配置不被拦截的资源及链接
            filterChainDefinitionMap.put("/static/**", "anon");
            // 退出过滤器
            filterChainDefinitionMap.put("/logout", "logout");
            //开启注册页面不需要权限
            filterChainDefinitionMap.put("/user/login", "anon");
            filterChainDefinitionMap.put("/user/register", "anon");
    
            //配置需要认证权限的
            filterChainDefinitionMap.put("/**", "authc");
    
    
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return shiroFilterFactoryBean;
        }
    
        /**
         * 配置shiro的生命周期
         *
         * @return
         */
        @Bean
        public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
    
        /**
         * 定义加密规则 存入密码时也必须加密
         */
        @Bean
        public HashedCredentialsMatcher myMatcher(){
            HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
            matcher.setHashAlgorithmName("SHA-256");
            // true means hex encoded, false means base64 encoded
            matcher.setStoredCredentialsHexEncoded(false);
            matcher.setHashIterations(10000);
            return  matcher;
        }
    
        public class MyRememberFilter extends FormAuthenticationFilter {
            protected boolean isAccessAllowed(HttpServletRequest request, HttpServletResponse response, Object mappedValue){
                Subject subject=getSubject(request,response);
                if(!subject.isAuthenticated() && subject.isRemembered()){
                    if(subject.getSession().getAttribute("user")==null &&subject.getPrincipal()!=null){
                        subject.getSession().setAttribute("user",subject.getPrincipal());
                    }
    
                }
                return subject.isAuthenticated() || subject.isRemembered();
            }
        }
       /* private class MyMatcher extends HashedCredentialsMatcher {
            @Override
            public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
                UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
                String pwd = encrypt(String.valueOf(usernamePasswordToken.getPassword()));
                String mysqlpwd = (String) info.getCredentials();
                logger.info("密码"+mysqlpwd);
                logger.info("密码"+pwd);
                return this.equals(pwd, mysqlpwd);
            }
    
            //将传进来的密码进行加密的方法
            private String encrypt(String data) {
                // 加密
                String salt = UUID.randomUUID().toString();
                String s = new Sha256Hash(data, salt, MyConstant.INTERCOUNT).toBase64();
                return s;
            }
        }*/
    
        /**
         * 自定义身份认证Realm(包含用户名密码校验,权限校验等)
         */
        @Bean
        public ShiroRealm myShiroRealm() {
            ShiroRealm myShiroRealm = new ShiroRealm();
            myShiroRealm.setCredentialsMatcher(myMatcher());
            return myShiroRealm;
        }
    
        /**
         * 使用shiro 支持thymeleaf 模版引擎
         */
        @Bean
        public ShiroDialect shiroDialect() {
            return new ShiroDialect();
        }
    
        /**
         * 配置记住我Cookie对象参数,rememberMeCookie()方法是设置Cookie的生成模版
         */
        public SimpleCookie rememberMeCookie() {
            //这个参数是cookie的名称,对应前端的checkbox的name=rememberMe
            SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
            //cookie生效时间为10秒
            simpleCookie.setMaxAge(100000);
            return simpleCookie;
        }
    
        /**
         * 配置Cookie管理对象,rememberMeManager()方法是生成rememberMe管理器
         */
        @Bean
        public CookieRememberMeManager rememberMeManager() {
            CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
            cookieRememberMeManager.setCookie(rememberMeCookie());
            return cookieRememberMeManager;
        }
    
        /**
         * 配置sessionCookie对象参数,sessionCookie()方法是设置Cookie的生成模版
         */
        public SimpleCookie sessionIdCookie() {
            //这个参数是cookie的名称,对应前端的checkbox的name=rememberMe
            SimpleCookie simpleCookie = new SimpleCookie("JSESSIONID");
            //只允许http请求访问cookie
            simpleCookie.setHttpOnly(true);
            //cookie生效时间为10秒 默认为-1
            simpleCookie.setMaxAge(-1);
            return simpleCookie;
        }
    
        /**
         * 配置Cookie管理对象,rememberMeManager()方法是生成rememberMe管理器
         */
        @Bean
        public DefaultWebSessionManager sessionManager() {
            DefaultWebSessionManager webSessionManager = new DefaultWebSessionManager();
            webSessionManager.setSessionIdCookie(sessionIdCookie());
            // session全局超时时间, 单位:毫秒 ,30分钟 默认值为1800000
            webSessionManager.setGlobalSessionTimeout(1800000);
            //开启检测器,默认开启
            webSessionManager.setSessionIdUrlRewritingEnabled(true);
            // 检测间隔事件 时间为1小时
            webSessionManager.setSessionValidationInterval(3600000);
            // 设置监听器
            //webSessionManager.setSessionListeners();
            return webSessionManager;
        }
    
        @Bean
        public CacheManager cacheManager() {
            return new MemoryConstrainedCacheManager();
        }
    
        @Bean(name = "securityManager")
        public SecurityManager securityManager() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //注入自定义myRealm
            securityManager.setRealm(myShiroRealm());
            //注入自定义cacheManager
            securityManager.setCacheManager(cacheManager());
            //注入记住我管理器
            securityManager.setRememberMeManager(rememberMeManager());
            //注入自定义sessionManager
            securityManager.setSessionManager(sessionManager());
            return securityManager;
        }
    
    
        //开启shiro aop注解支持,不开启的话权限验证就会失效
        @Bean
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
            return defaultAdvisorAutoProxyCreator;
        }
    
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor sourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            sourceAdvisor.setSecurityManager(securityManager);
            return sourceAdvisor;
        }
    
        //配置异常处理,不配置的话没有权限后台报错,前台不会跳转到403页面
        @Bean(name = "simpleMappingExceptionResolver")
        public SimpleMappingExceptionResolver
        createSimpleMappingExceptionResolver() {
            SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
            Properties mappings = new Properties();
            mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
            mappings.setProperty("UnauthorizedException", "403");
            simpleMappingExceptionResolver.setExceptionMappings(mappings);  // None by default
            simpleMappingExceptionResolver.setDefaultErrorView("403");    // No default
            simpleMappingExceptionResolver.setExceptionAttribute("ex");     // Default is "exception"
            return simpleMappingExceptionResolver;
        }
    }


    4: thymeleaf

    login.html

    <!DOCTYPE html>
    <html lang="en" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
          xmlns:th="http://www.thymeleaf.org" >
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>Insert title here</title>
    </head>
    <body>
    <form method="post" action="login" >
        <label for="name">用户名</label>
        <shiro:authenticated>
            <input id="name" type="text" name="username" value="<shiro:principal/>" >
        </shiro:authenticated>
        <shiro:notAuthenticated>
            <input id="name" type="text" name="username" value=" " >
        </shiro:notAuthenticated>
        <br>
        <label for="pass">密码</label>
        <input id="pass" type="text" name="password">
        <button type="submit">提交</button>
    
    </form>
    </body>
    </html>

    5 controller

    @Controller
    @RequestMapping("/user")
    public class LoginController {
        private final Logger logger = LoggerFactory.getLogger(this.getClass());
        @Autowired
        private UserService userService;
    
        @GetMapping("/login")
        public String login() {
            return "login";
        }
    
        @PostMapping("/login")
        public String loginLogic(User user) {
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
            // 登录失败会抛出异常,则交由异常解析器处理
            token.setRememberMe(true);
            subject.login(token);
    
            return "main";
        }
    
        @GetMapping("/register")
        public String regiter() {
            return "register";
        }
    
    
        @PostMapping("/register")
        public String logicRegiter(User user) {
            userService.insertUser(user);
            return "redirect:login";
        }
    }
  • 相关阅读:
    实现 ajax 多项选择框
    Ajax 文件上传之PHP心得
    php tree生成树分享
    基于JQuery框架的AJAX
    jQuery Ajax 全解析
    asp 下载函数
    10元奥运纪念钞明发行 与人民币等值流通
    jQuery(Ajax)/PHP/MySQL实现搜索自动提示功能
    隔行扫描和逐行扫描(interlace and progressive )
    VGA 输出调试
  • 原文地址:https://www.cnblogs.com/dgwblog/p/12584884.html
Copyright © 2011-2022 走看看