springBoot笔记(七)---shiro安全框架

安全(权限框架)Shiro

官网: http://shiro.apache.org/

官方简介:

Apache Shiro™是一个功能强大且易于使用的Java安全框架,它执行身份验证,授权,加密和会话管理。 使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序-从最小的移动应用程序到最大的Web和企业应用程序。

官方快速教程: https://github.com/apache/shiro/blob/master/samples/quickstart

import javax.security.auth.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class QuickerStart {

    private static final transient Logger log = LoggerFactory.getLogger(QuickerStart.class);


    public static void main(String[] args) {

            // 固定三步 
            Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
            SecurityManager securityManager = factory.getInstance();
            SecurityUtils.setSecurityManager(securityManager);

            // 获取当前的用户对象
            Subject currentUser = SecurityUtils.getSubject();

            // 获取当前用户的session,并通过session进行存取值操作
            Session session = currentUser.getSession();
            session.setAttribute("someKey", "aValue");
            String value = (String) session.getAttribute("someKey");
            if (value.equals("aValue")) {
                log.info("Retrieved the correct value! [" + value + "]");
            }

             // 判断当前用户是否被认证
            if (!currentUser.isAuthenticated()) {
                // 如果被认证就会通过账号和密码生成一个令牌,并记住
                UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
                token.setRememberMe(true);
                try {
                    // 执行登录操作
                    currentUser.login(token);
                } catch (UnknownAccountException uae) {
                    log.info("There is no user with username of " + token.getPrincipal());
                } catch (IncorrectCredentialsException ice) {
                    log.info("Password for account " + token.getPrincipal() + " was incorrect!");
                } catch (LockedAccountException lae) {
                    log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                            "Please contact your administrator to unlock it.");
                }
                // ... catch more exceptions here (maybe custom ones specific to your application?
                catch (AuthenticationException ae) {
                    //unexpected condition?  error?
                }
            }

            //say who they are:
            //print their identifying principal (in this case, a username):
            log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");

            //test a role:
            if (currentUser.hasRole("schwartz")) {
                log.info("May the Schwartz be with you!");
            } else {
                log.info("Hello, mere mortal.");
            }

            //test a typed permission (not instance-level)
            if (currentUser.isPermitted("lightsaber:wield")) {
                log.info("You may use a lightsaber ring.  Use it wisely.");
            } else {
                log.info("Sorry, lightsaber rings are for schwartz masters only.");
            }

            //a (very powerful) Instance Level permission:
            if (currentUser.isPermitted("winnebago:drive:eagle5")) {
                log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                        "Here are the keys - have fun!");
            } else {
                log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
            }

            //all done - log out!
            currentUser.logout();

            System.exit(0);
        }
}

1.Shiro架构

ApplicationCode---->Subject (当前用户)---->SecurityManager(管理所有用户,进行权限认证)--->Realm(连接安全数据)

2.shiro和spring的整合

  • 进行shiro-spring依赖导入

    <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.6.0</version>
            </dependency>
            
            <dependency>
                <groupId>org.thymeleaf</groupId>
                <artifactId>thymeleaf-spring5</artifactId>
            </dependency>
            <dependency>
                <groupId>org.thymeleaf.extras</groupId>
                <artifactId>thymeleaf-extras-java8time</artifactId>
            </dependency>
    
  • config的编写,三步走

    手动创建Realm类

    public class UserRealm extends AuthorizingRealm {
        // 授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            return null;
        }
        // 认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            return null;
        }
    }
    

    config配置

    @Configuration
    public class ShiroConfig {
        // 整体架构根据三部分组成
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
            // 设置安全管理器
            factoryBean.setSecurityManager(defaultWebSecurityManager);
            // 添加内置过滤器
            /*
                onon:无需认证就可以访问
                authc:必须认证才能访问
                user:必须拥有记住我工功能才可以使用
                perms:拥有对某个资源的权限才可以访问(例如:管理员)
                role: 拥有某个角色权限才可以访问
             */
            // 进行页面访问认证,有点像druid日志权限控制
            Map<String,String> filterMap = new LinkedHashMap<>();
            filterMap.put("/add","authc");   // 进入add页面必须进行认证,如果没认证就会进入到登录认证的页面
            filterMap.put("/select","authc");
            filterMap.put("/select","perms[user:select]");   // 必须有user:select这样的权限才能访问
            factoryBean.setFilterChainDefinitionMap(filterMap);
            // 设置登录认证页面
            factoryBean.setLoginUrl("/tologin");
            return factoryBean;
        }
        
        // DefaultWebSecurityManager
        @Bean(name="securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("UserRealm") UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            // 关联realm,上面进行了参数绑定
            securityManager.setRealm(userRealm);
            return securityManager;
        }
        
        // 创建自定义的Realm对象
        @Bean(name="UserRealm")
        public UserRealm userRealm(){
            return new UserRealm();
        }
    }  
    

```java
  // controller中进入到登录页面
  @RequestMapping("/tologin")
      public String tologin(){
          return "login";
      }
  • 实现用户的认证

    认证是在controller中接受到前端传递过来的信息,然后在Realm中进行账户密码的认证操作

    1.controller中获取用户登录信息

        @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);
                return "index";
            }catch (IncorrectCredentialsException e){   // 这里可以抛出很多异常
                model.addAttribute("msg","密码错误!");
                return "login";
            }catch (UnknownAccountException e){
                model.addAttribute("msg","用户名不存在!");
                return "login";
            }
        }
    

    2.在Realm中获取token进行数据库信息验证

    // 认证和controller类是相互关联的
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
                throws AuthenticationException {
            // 这里的token就是controller中的token,包含用户信息
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
            // 伪造数据库数据,正常连接数据库调用service方法,获取用户信息
            String name = "zhangsan";
            String password = "123";
            // shiro中不会让我们去验证密码,所以只要验证用户名就好了
            if (!token.getUsername().equals(name)){
                return null;   // 就会抛出controller中的异常
            }
            return new SimpleAuthenticationInfo(user,password,"");   // user是上传给授权的方法,用户获取用户权限
        }
    }
    
  • 进行用户授权认证,在config配置部分进行授权访问限制,principalCollection得到user的数据,判断用户是否有权限

     // 授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            
            // 1.对所有用户添加该权限
            //authorizationInfo.addStringPermission("user:add");
             
             // 2.获取当前登录对象,并获取认证方法返回值传递过来的user
             Subject subject = SecurityUtils.getSubject();
             User currentuser= (User)subject.getPrincipal();
             // 设置当前用户的权限
             authorizationInfo.addStringPermission(currentuser.getXXX()); // currentuser.getXXX()用户在数据库表                                                                                                中的权限
            
            return authorizationInfo;
        }
    

3.shiro和thymeleaf整合

​ shiro和thymeleaf整合可以控制前端页面根据不同权限进行显示。不同权限的人和看到不同的页面

  • 导入整合依赖

            <dependency>
                <groupId>com.github.theborakompanioni</groupId>
                <artifactId>thymeleaf-extras-shiro</artifactId>
                <version>2.0.8</version>
            </dependency>
    
  • 在shiro自定义配置文件中,也就是ShiroConfig,配置整合ShiroDialect

    @Bean
    public ShiroDilect getShiroDilect(){
        return new ShiroDilect();
    }
    
  • 前端操作

    1.添加命名空间:跟springSecurity和相似

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

    2.例子:用户是否有某个权限

    <div shiro:hasPermisssion="user:add">    
    </div>
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值