Shiro整合springboot以及自定义Realm

判断用户是否是游客身份,如果是游客身份则显示此标签内容

一、Shiro认证流程

二、SpringBoot应用整合Shiro

  • JavaSE应用中使用

  • web应用中使用

    • SSM整合Shiro(配置多,用的少)

    • SpringBoot应用整合Shiro

2.1 创建SpringBoot应用

  • lombok

  • spring web

  • thymeleaf

2.2 整合Druid和MyBatis

  • 依赖

  • <!-- druid starter -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
     <!--mysql -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <!-- mybatis -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.0</version>
    </dependency>
  • 配置
  • spring:
      datasource:
        druid:
          url: jdbc:mysql://47.96.11.185:3306/test
          # MySQL如果是8.x   com.mysql.cj.jdbc.Driver
          driver-class-name: com.mysql.jdbc.Driver
          username: root
          password: admin123
          initial-size: 1
          min-idle: 1
          max-active: 20
    mybatis:
      mapper-locations: classpath:mappers/*Mapper.xml
      type-aliases-package: com.qfedu.springbootssm.beans

     

  • 2.3 整合Shiro

    • 导入依赖

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

      Shiro配置(java配置方式)

        • SpringBoot默认没有提供对Shiro的自动配置

        • @Configuration
          public class ShiroConfig {
          
              @Bean
              public JdbcRealm getJdbcRealm(DataSource dataSource){
                  JdbcRealm jdbcRealm = new JdbcRealm();
                  //JdbcRealm会自行从数据库查询用户及权限数据(数据库的表结构要符合JdbcRealm的规范)
                  jdbcRealm.setDataSource(dataSource);
                  //JdbcRealm默认开启认证功能,需要手动开启授权功能
                  jdbcRealm.setPermissionsLookupEnabled(true);
                  return  jdbcRealm;
              }
          
              @Bean
              public DefaultWebSecurityManager getDefaultWebSecurityManager(JdbcRealm jdbcRealm){
                  DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
                  securityManager.setRealm(jdbcRealm);
                  return securityManager;
              }
          
              @Bean
              public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager){
                  ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
                  //过滤器就是shiro就行权限校验的核心,进行认证和授权是需要SecurityManager的
                  filter.setSecurityManager(securityManager);
          
                  Map<String,String> filterMap = new HashMap<>();
                  filterMap.put("/","anon");
                  filterMap.put("/login.html","anon");
                  filterMap.put("/regist.html","anon");
                  filterMap.put("/user/login","anon");
                  filterMap.put("/user/regist","anon");
                  filterMap.put("/static/**","anon");
                  filterMap.put("/**","authc");
          
                  filter.setFilterChainDefinitionMap(filterMap);
                  filter.setLoginUrl("/login.html");
                  //设置未授权访问的页面路径
                  filter.setUnauthorizedUrl("/login.html");
                  return filter;
              }
          
          }
          • 认证测试----------UserServiceImpl.java

            @Service
            public class UserServiceImpl {
            
                public void checkLogin(String userName,String userPwd) throws Exception{
                    Subject subject = SecurityUtils.getSubject();
                    UsernamePasswordToken token = new UsernamePasswordToken(userName,userPwd);
                    subject.login(token);
                }
            
            }

            UserController.java

          • @Controller
            @RequestMapping("user")
            public class UserController {
            
                @Resource
                private UserServiceImpl userService;
            
                @RequestMapping("login")
                public String login(String userName,String userPwd){
                    try {
                        userService.checkLogin(userName,userPwd);
                        System.out.println("------登录成功!");
                        return "index";
                    } catch (Exception e) {
                        System.out.println("------登录失败!");
                        return "login";
                    }
            
                }
            }

        • 自定义Realm     
          • 自定义Realm       
            • 自定义Real
        /**
         * 1.创建一个类继承AuthorizingRealm类(实现了Realm接口的类)
         * 2.重写doGetAuthorizationInfo和doGetAuthenticationInfo方法
         * 3.重写getName方法返回当前realm的一个自定义名称
         */
        public class MyRealm extends AuthorizingRealm {
            
            @Resource
            private UserDAO userDAO;
            @Resource
            private RoleDAO roleDAO;
            @Resource
            private PermissionDAO permissionDAO;
        
            public String getName() {
                return "myRealm";
            }
            
            /**
             * 获取授权数据(将当前用户的角色及权限信息查询出来)
             */
            protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
                //获取用户的用户名
                String username = (String) principalCollection.iterator().next();
                //根据用户名查询当前用户的角色列表
                Set<String> roleNames = roleDAO.queryRoleNamesByUsername(username);
                //根据用户名查询当前用户的权限列表
                Set<String> ps = permissionDAO.queryPermissionsByUsername(username);
        
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                info.setRoles(roleNames);
                info.setStringPermissions(ps);
                return info;
            }
        
            /**
             * 获取认证的安全数据(从数据库查询的用户的正确数据)
             */
            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
                //参数authenticationToken就是传递的  subject.login(token)
                // 从token中获取用户名
                UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
                String username = token.getUsername();
                //根据用户名,从数据库查询当前用户的安全数据
                User user = userDAO.queryUserByUsername(username);
        
                AuthenticationInfo info = new SimpleAuthenticationInfo(
                        username,           //当前用户用户名
                        user.getUserPwd(),   //从数据库查询出来的安全密码
                        getName());
        
                return info;
            }
        }
      • 二、加密

        • 明文-----(加密规则)-----密文

        • 加密规则可以自定义,在项目开发中我们通常使用BASE64和MD5编码方式

          • BASE64:可反编码的编码方式(对称)

            • 明文----密文

            • 密文----明文

          • MD5: 不可逆的编码方式(非对称)

            • 明文----密文

        • 如果数据库用户的密码存储的密文,Shiro该如何完成验证呢?

        • 使用Shiro提供的加密功能,对输入的密码进行加密之后再进行认证。

        2.1 加密介绍

    • 2.2 Shiro使用加密认证

      • 配置matcher

      • @Configuration
        public class ShiroConfig {
        
            //...
            @Bean
            public HashedCredentialsMatcher getHashedCredentialsMatcher(){
                HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
                //matcher就是用来指定加密规则
                //加密方式
                matcher.setHashAlgorithmName("md5");
                //hash次数
                matcher.setHashIterations(1);    //此处的循环次数要与用户注册是密码加密次数一致
                return matcher;
            }
        
            //自定义Realm
            @Bean
            public MyRealm getMyRealm( HashedCredentialsMatcher matcher ){
                MyRealm myRealm = new MyRealm();
                myRealm.setCredentialsMatcher(matcher);
                return myRealm;
            }
        
            //...
        }

        2.3 用户注册密码加密处理

        • registh.html

        • <form action="/user/regist" method="post">
              <p>帐号:<input type="text" name="userName"/></p>
              <p>密码:<input type="text" name="userPwd"/></p>
              <p><input type="submit" value="提交注册"/></p>
          </form>

          UserController

        • @Controller
          @RequestMapping("user")
          public class UserController {
          
              @Resource
              private UserServiceImpl userService;
          
          
          
              @RequestMapping("/regist")
              public String regist(String userName,String userPwd) {
                  System.out.println("------注册");
          
                  //注册的时候要对密码进行加密存储
                  Md5Hash md5Hash = new Md5Hash(userPwd);
                  System.out.println("--->>>"+ md5Hash.toHex());
          
                  //加盐加密
                  int num = new Random().nextInt(90000)+10000;   //10000—99999
                  String salt = num+"";
                  Md5Hash md5Hash2 = new Md5Hash(userPwd,salt);
                  System.out.println("--->>>"+md5Hash2);
          
                  //加盐加密+多次hash
                  Md5Hash md5Hash3 = new Md5Hash(userPwd,salt,3);
                  System.out.println("--->>>"+md5Hash3);
          
                  //SimpleHash hash = new SimpleHash("md5",userPwd,num,3);
                  
                  //将用户信息保存到数据库时,保存加密后的密码,如果生成的随机盐,盐也要保存
                  
                  return "login";
              }
          
          }

          2.4 如果密码进行了加盐处理,则Realm在返回认证数据时需要返回盐

          • 在自定义Realm中:

      • public class MyRealm extends AuthorizingRealm {
            
            @Resource
            private UserDAO userDAO;
            @Resource
            private RoleDAO roleDAO;
            @Resource
            private PermissionDAO permissionDAO;
        
            public String getName() {
                return "myRealm";
            }
        
            /**
             * 获取认证的安全数据(从数据库查询的用户的正确数据)
             */
            protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
                //参数authenticationToken就是传递的  subject.login(token)
                // 从token中获取用户名
                UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
                String username = token.getUsername();
                //根据用户名,从数据库查询当前用户的安全数据
                User user = userDAO.queryUserByUsername(username);
        
        //        AuthenticationInfo info = new SimpleAuthenticationInfo(
        //                username,           //当前用户用户名
        //                user.getUserPwd(),   //从数据库查询出来的安全密码
        //                getName());
        
                //如果数据库中用户的密码是加了盐的
                AuthenticationInfo info = new SimpleAuthenticationInfo(
                        username,           //当前用户用户名
                        user.getUserPwd(),   //从数据库查询出来的安全密码
                        ByteSource.Util.bytes(user.getPwdSalt()),
                        getName());
        
                return info;
            }
        }

        三、退出登录

        • 在Shiro过滤器中进行配置,配置logut对应的路径

        • filterMap.put("/exit","logout");

          在页面的“退出”按钮上,跳转到logout对应的url

      • <a href="exit">退出</a>

        四、授权

        用户登录成功之后,要进行响应的操作就需要有对应的权限;在进行操作之前对权限进行检查—授权

        权限控制通常有两类做法:

        • 不同身份的用户登录,我们现在不同的操作菜单(没有权限的菜单不现实)

        • 对所有用户显示所有菜单,当用户点击菜单以后再验证当前用户是否有此权限,如果没有则提示权限不足

        4.1 HTML授权

        • 在菜单页面只显示当前用户拥有权限操作的菜单

        • shiro标签

      • <shiro:hasPermission name="sys:c:save">
            <dd><a href="javascript:;">入库</a></dd>
        </shiro:hasPermission>

        4.2 过滤器授权

        • 在shiro过滤器中对请求的url进行权限设置

        • filterMap.put("/c_add.html","perms[sys:c:save]");
          
          //设置未授权访问的页面路径—当权限不足时显示此页面
          filter.setUnauthorizedUrl("/lesspermission.html");
      • 4.3 注解授权

      • 配置Spring对Shiro注解的支持:ShiroConfig.java

      • @Bean
        public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
            DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
            autoProxyCreator.setProxyTargetClass(true);
            return autoProxyCreator;
        }
        
        @Bean
        public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor( DefaultWebSecurityManager securityManager){
            AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            return advisor;
        }
      • 在请求的控制器添加权限注解
      • @Controller
        @RequestMapping("customer")
        public class CustomerController {
        
            @RequestMapping("list")
            //如果没有 sys:k:find 权限,则不允许执行此方法
            @RequiresPermissions("sys:k:find")
            //    @RequiresRoles("")
            public String list(){
                System.out.println("----------->查询客户信息");
                return "customer_list";
            }
        
        }
      • 通过全局异常处理,指定权限不足时的页面跳转
      • @ControllerAdvice
        public class GlobalExceptionHandler {
        
            @ExceptionHandler
            public String doException(Exception e){
                if(e instanceof AuthorizationException){
                    return  "lesspermission";
                }
                return null;
            }
        
        }

        4.4 手动授权

      • 在代码中进行手动的权限校验

      • Subject subject = SecurityUtils.getSubject();
        if(subject.isPermitted("sys:k:find")){
            System.out.println("----------->查询客户信息");
            return "customer_list";
        }else{
            return "lesspermission";
        }
      • 五、缓存使用

      • 使用Shiro进行权限管理过程中,每次授权都会访问realm中的doGetAuthorizationInfo方法查询当前用户的角色及权限信息,如果系统的用户量比较大则会对数据库造成比较大的压力

        Shiro支持缓存以降低对数据库的访问压力(缓存的是授权信息)

      • 5.1 导入依赖

      • <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.4.0</version>
        </dependency>

        5.2 配置缓存策略

      • 在resources目录下创建一个xml文件(ehcache.xml)

      • <?xml version="1.0" encoding="UTF-8"?>
        <ehcache updateCheck="false" dynamicConfig="false">
        
            <diskStore path="C:\TEMP" />
        
            <cache name="users"  timeToLiveSeconds="300"  maxEntriesLocalHeap="1000"/>
        
            <defaultCache name="defaultCache"
                          maxElementsInMemory="10000"
                          eternal="false"
                          timeToIdleSeconds="120"
                          timeToLiveSeconds="120"
                          overflowToDisk="false"
                          maxElementsOnDisk="100000"
                          diskPersistent="false"
                          diskExpiryThreadIntervalSeconds="120"
                          memoryStoreEvictionPolicy="LRU"/>
                    <!--缓存淘汰策略:当缓存空间比较紧张时,我们要存储新的数据进来,就必然要删除一些老的数据
                        LRU 最近最少使用
                        FIFO 先进先出
                        LFU  最少使用
                    -->
        </ehcache>

        5.3 加入缓存管理

      • ShiroConfig.java

      • @Bean
        public EhCacheManager getEhCacheManager(){
            EhCacheManager ehCacheManager = new EhCacheManager();
            ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
            return ehCacheManager;
        }
        
        @Bean
        public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(myRealm);
            securityManager.setCacheManager(getEhCacheManager());
            return securityManager;
        }
  • 六、session管理

    • Shiro进行认证和授权是基于session实现的,Shiro包含了对session的管理
    • 如果我们需要对session进行管理

    • 自定义session管理器

    • 将自定义的session管理器设置给SecurityManager

    • 配置自定义SessionManager:ShiroConfig.java

  • @Bean
    public DefaultWebSessionManager getDefaultWebSessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        System.out.println("----------"+sessionManager.getGlobalSessionTimeout()); // 1800000
        //配置sessionManager
        sessionManager.setGlobalSessionTimeout(5*60*1000);
        return sessionManager;
    }
    
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        securityManager.setCacheManager(getEhCacheManager());
        securityManager.setSessionManager(getDefaultWebSessionManager());
        return securityManager;
    }
  • 二、RememberMe

  •  

    将用户对页面访问的权限分为三个级别:

    • 未认证—可访问的页面—(陌生人)—问候

    • login.html、regist.html

    • 记住我—可访问的页面—(前女友)—朋友间的拥抱

    • info.html

    • 已认证—可访问的页面—(现女友)—牵手

    • 转账.html

  • 2.1 在过滤器中设置“记住我”可访问的url

  •  

    // anon     表示未认证可访问的url
    // user     表示记住我可访问的url(已认证也可以访问)
    //authc     表示已认证可访问的url
    //perms        表示必须具备指定的权限才可访问
    //logout    表示指定退出的url
    filterMap.put("/","anon");
    filterMap.put("/index.html","user");
    filterMap.put("/login.html","anon");
    filterMap.put("/regist.html","anon");
    filterMap.put("/user/login","anon");
    filterMap.put("/user/regist","anon");
    filterMap.put("/layui/**","anon");
    filterMap.put("/**","authc");
    filterMap.put("/c_add.html","perms[sys:c:save]");
    filterMap.put("/exit","logout");
  • 2.2 在ShiroConfig.java中配置基于cookie的rememberMe管理器

  •  

    @Bean
    public CookieRememberMeManager cookieRememberMeManager(){
        CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
       
        //cookie必须设置name
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        cookie.setMaxAge(30*24*60*60);
        
        rememberMeManager.setCookie(cookie);
        return  rememberMeManager;
    }
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        securityManager.setCacheManager(getEhCacheManager());
        securityManager.setSessionManager(getDefaultWebSessionManager());
        //设置remember管理器
        securityManager.setRememberMeManager(cookieRememberMeManager());
        return securityManager;
    }
  • 2.3 登录认证时设置token“记住我”

    • 登录页面

    • <form action="/user/login" method="post">
          <p>帐号:<input type="text" name="userName"/></p>
          <p>密码:<input type="text" name="userPwd"/></p>
          <p>记住我:<input type="checkbox" name="rememberMe"/></p>
          <p><input type="submit" value="登录"/></p>
      </form>
    • 控制器
    • @Controller
      @RequestMapping("user")
      public class UserController {
      
          @Resource
          private UserServiceImpl userService;
      
          @RequestMapping("login")
          public String login(String userName,String userPwd,boolean rememberMe){
              try {
                  userService.checkLogin(userName,userPwd,rememberMe);
                  System.out.println("------登录成功!");
                  return "index";
              } catch (Exception e) {
                  System.out.println("------登录失败!");
                  return "login";
              }
      
          }
          
          //...
      }
    • service
    • @Service
      public class UserServiceImpl {
      
          public void checkLogin(String userName, String userPwd,boolean rememberMe) throws Exception {
              //Shiro进行认证 ——入口
              Subject subject = SecurityUtils.getSubject();
              UsernamePasswordToken token = new UsernamePasswordToken(userName,userPwd);
              token.setRememberMe(rememberMe);
              subject.login(token);
          }
      }
    • 三、Shiro多Realm配置

      3.1 使用场景

      • 当shiro进行权限管理,数据来自于不同的数据源时,我们可以给SecurityManager配置多个Realm

        • 3.2 多个Realm的处理方式

          3.2.1 链式处理
          • 多个Realm依次进行认证

          3.2.2 分支处理
          • 根据不同的条件从多个Realm中选择一个进行认证处理

          3.3 多Realm配置(链式处理)

          • 定义多个Realm

            • UserRealm

            • public class UserRealm extends AuthorizingRealm {
              
                  Logger logger = LoggerFactory.getLogger(UserRealm.class);
              
                  @Override
                  public String getName() {
                      return "UserRealm";
                  }
              
                  @Override
                  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
                      return null;
                  }
              
                  @Override
                  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
                      logger.info("--------------------------------UserRealm");
                      //从token中获取username
                      UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
                      String username = token.getUsername();
                      //根据username从users表中查询用户信息
              
                      SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,"123456",getName());
                      return info;
                  }
              }
            • ManagerRealm
            • public class ManagerRealm extends AuthorizingRealm {
              
                  Logger logger = LoggerFactory.getLogger(ManagerRealm.class);
              
                  @Override
                  public String getName() {
                      return "ManagerRealm";
                  }
              
                  @Override
                  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
                      return null;
                  }
              
                  @Override
                  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
                      logger.info("--------------------------------ManagerRealm");
                      //从token中获取username
                      UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
                      String username = token.getUsername();
                      //根据username从吗managers表中查询用户信息
              
                      SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,"222222",getName());
                      return info;
                  }
              }
            • 在ShiroConfig.java中为SecurityManager配置多个Realm
            • @Configuration
              public class ShiroConfig {
              
                  @Bean
                  public UserRealm userRealm(){
                      UserRealm userRealm = new UserRealm();
                      return  userRealm;
                  }
              
                  @Bean
                  public ManagerRealm managerRealm(){
                      ManagerRealm managerRealm = new ManagerRealm();
                      return managerRealm;
                  }
              
                  @Bean
                  public DefaultWebSecurityManager getDefaultWebSecurityManager(){
                      DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
                      
                      //securityManager中配置多个realm
                      Collection<Realm> realms = new ArrayList<>();


              realms.add(userRealm()); realms.add(managerRealm());

              securityManager.setRealms(realms);
              return securityManager; } //... }
    • 3.5 多Realm配置(分支处理)

    • 根据不同的条件执行不同的Realm
    • 实现案例:用户不同身份登录执行不同的Realm

      • 自定义Realm(UserRealm\ManagerRealm)

        • 当在登录页面选择“普通用户”登录,则执行UserRealm的认证

        • 当在登录页面选择“管理员”登录,则执行ManagerRealm的认证

      • Realm的声明及配置

      • 自定义Token

      • public class MyToken extends UsernamePasswordToken {
        
            private String loginType;
        
            public MyToken(String userName,String userPwd, String loginType) {
                super(userName,userPwd);
                this.loginType = loginType;
            }
        
            public String getLoginType() {
                return loginType;
            }
        
            public void setLoginType(String loginType) {
                this.loginType = loginType;
            }
        }
      • 自定义认证器
      • public class MyModularRealmAuthenticator extends ModularRealmAuthenticator {
        
            Logger logger = LoggerFactory.getLogger(MyModularRealmAuthenticator.class);
        
            @Override
            protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
                logger.info("------------------------------MyModularRealmAuthenticator");
        
                this.assertRealmsConfigured();
                Collection<Realm> realms = this.getRealms();
        
                MyToken token = (MyToken) authenticationToken;
                String loginType = token.getLoginType(); // User
                logger.info("------------------------------loginType:"+loginType);
        
                Collection<Realm> typeRealms = new ArrayList<>();
                for(Realm realm:realms){
                    if(realm.getName().startsWith(loginType)){  //UserRealm
                        typeRealms.add(realm);
                    }
                }
        
               if(typeRealms.size()==1){
                   return this.doSingleRealmAuthentication((Realm)typeRealms.iterator().next(), authenticationToken);
               }else{
                   return this.doMultiRealmAuthentication(typeRealms, authenticationToken);
               }
        
            }
        
        }
      • 配置自定义认证器
      • @Configuration
        public class ShiroConfig {
        
            @Bean
            public UserRealm userRealm(){
                UserRealm userRealm = new UserRealm();
                return  userRealm;
            }
        
            @Bean
            public ManagerRealm managerRealm(){
                ManagerRealm managerRealm = new ManagerRealm();
                return managerRealm;
            }
        
            @Bean
            public MyModularRealmAuthenticator myModularRealmAuthenticator(){
                MyModularRealmAuthenticator myModularRealmAuthenticator = new MyModularRealmAuthenticator();
                return myModularRealmAuthenticator;
            }
        
            @Bean
            public DefaultWebSecurityManager getDefaultWebSecurityManager(){
                DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
                //配置自定义认证器(放在realms设置之前)
                securityManager.setAuthenticator(myModularRealmAuthenticator());
        
                //securityManager中配置多个realm
                Collection<Realm> realms = new ArrayList<>();
                realms.add(userRealm());
                realms.add(managerRealm());
        
                securityManager.setRealms(realms);
                return securityManager;
            }
        
            //...
        
        }
      • 测试:控制器接受数据进行认证

        • login.html

        • <form action="user/login" method="post">
              <p>帐号:<input type="text" name="userName"/></p>
              <p>密码:<input type="text" name="userPwd"/></p>
              <p><input type="radio" name="loginType" value="User" checked/>普通用户
              <input type="radio" name="loginType" value="Manager"/>管理员</p>
          
              <p><input type="submit" value="登录"/></p>
          </form>
        • UserController.java
        • @Controller
          @RequestMapping("user")
          public class UserController {
              Logger logger = LoggerFactory.getLogger(UserController.class);
          
              @RequestMapping("login")
              public String login(String userName,String userPwd, String loginType){
                  logger.info("~~~~~~~~~~~~~UserController-login");
                  try{
                      //UsernamePasswordToken token = new UsernamePasswordToken(userName,userPwd);
                      MyToken token = new MyToken(userName,userPwd,loginType);
                      Subject subject = SecurityUtils.getSubject();
                      subject.login(token);
                      return "index";
                  }catch (Exception e){
                      return "login";
                  }
          
              }
          
          }

猜你喜欢

转载自www.cnblogs.com/jikeyi/p/13375167.html