• 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(UserRealmManagerRealm)

          • 当在登录页面选择“普通用户”登录,则执行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";
                    }
            
                }
            
            }
  • 相关阅读:
    .net core 3.1 使用Redis缓存
    JavaSE 高级 第11节 缓冲输入输出字节流
    JavaSE 高级 第10节 字节数组输出流ByteArrayOutputStream
    JavaSE 高级 第09节 字节数组输入流ByteArrayInputStream
    JavaSE 高级 第08节 文件输出流FileOutputStream
    JavaSE 高级 第07节 文件输入流FileInputStream
    JavaSE 高级 第06节 初识I、O流
    JavaSE 高级 第05节 日期类与格式化
    JavaSE 高级 第04节 StringBuffer类
    JavaSE 高级 第03节 Math类与猜数字游戏
  • 原文地址:https://www.cnblogs.com/jikeyi/p/13375167.html
Copyright © 2020-2023  润新知