zoukankan      html  css  js  c++  java
  • 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";
                    }
            
                }
            
            }
  • 相关阅读:
    SrsDataConnector The SQL Server Reporting Services account is a local user and is not supported.
    Marketing with Microsoft Dynamics CRM IDEA CONFERENCE
    Discuz!X 系列 HTTP_X_FORWARDED_FOR 绕过限制进行密码爆破
    PHPCMS v9.5.6 通杀getshell(前台)
    PHPCMS v9.5.8-设计缺陷可重置前台任意用户密码
    PHPCMS v9.6.0 任意用户密码重置
    PHPCMS V9 任意文件下载(Windows)
    Joomla!3.7.0 Core SQL注入漏洞动态调试草稿
    利用FOFA搜索WatchGuard防火墙
    如何删除Windows休眠文件(hiberfil.sys)
  • 原文地址:https://www.cnblogs.com/jikeyi/p/13375167.html
Copyright © 2011-2022 走看看