Advanced Advanced Use Remember Me and Multi Realm Configuration in Shiro

二、RememberMe

The user's access to the page is divided into three levels:

  • Unauthenticated-accessible page-(stranger)-greeting

    • login.html、regist.html

  • Remember me-accessible page-(ex-girlfriend)-hug between friends

    • info.html

  • Verified—Accessible Page—(Current Girlfriend)—Holding Hands

    • Transfer.html

2.1 Set "remember me" accessible url in the filter

// anon     表示未认证可访问的url
// user     表示记住我可访问的url(已认证也可以访问),例如某些页面在之前登陆过,安全级别又不高时,可以在用户再次浏览时呈现,这时可以设置为user
//authc     表示已认证可访问的url,对于某些安全级别很高的,即使几天或几小时之前登陆过,但是在再次进行操作时还必须得确认登陆或安全性时,比如付款时再次确认用户身份,这时可以设置为authc
//perms     表示必须具备指定的权限才可访问
//logout    表示指定退出的url
filterMap.put("/","anon");
// 为user表示"记住我",但是当用户需要一些其他的认证才能访问时,必须要进行验证才能访问
// user要比authc低一等级
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 Configure the cookie-based rememberMe manager in ShiroConfig.java

@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 Set the token "remember me" during login authentication

  • log in page

<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

@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);
    }
}

Three, Shiro multi-Realm configuration

3.1 Usage scenarios

  • When shiro performs permission management and the data comes from different data sources, we can configure multiple Realms for SecurityManager

 

Shiro configures multiple Realms

 

3.2 How to deal with multiple Realms

3.2.1 Chain processing

  • Multiple Realms are authenticated in turn. As long as one Realm is successfully authenticated, it means that the authentication is successful, but all the set Realms must be authenticated each time.

3.2.2 Branch processing

  • Select one of multiple Realms for authentication processing according to different conditions

3.3 Multiple Realm configuration (chain processing)

  • Define multiple Realms

    • 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;
          }
      }
  • Configure multiple Realms for SecurityManager in ShiroConfig.java

    @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;
        }
    ​
       //...
    ​
    }
    ​
  • Test code:

    • 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"/>普通用户
              <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);
                  Subject subject = SecurityUtils.getSubject();
                  subject.login(token);
                  return "index";
              }catch (Exception e){
                  return "login";
              }
      ​
          }
      ​
      }

3.4 Shiro authentication processing source code analysis

 
 
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
        this.assertRealmsConfigured();
        Collection<Realm> realms = this.getRealms();
        
        // this.doMultiRealmAuthentication(realms, authenticationToken);中的realms参数就是认证会执行的Realm
        return realms.size() == 1 ? this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken) : this.doMultiRealmAuthentication(realms, authenticationToken);
    }

3.5 Multiple Realm configuration (branch processing)

Execute different Realm according to different conditions

  • Process analysis

     

    Process analysis

    Process analysis

     

     

  • Implementation case: users log in with different identities to execute different Realms

    • Custom Realm (UserRealm\ManagerRealm)

      • When you select "Ordinary User" to log in on the login page, the UserRealm authentication is performed

      • When you select "Administrator" on the login page to log in, ManagerRealm authentication is performed

    • Realm's declaration and configuration

    • Custom 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;
          }
      }
    • Custom authenticator

      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);
             }
      ​
          }
      ​
      }
    • Configure a custom authenticator

      @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;
          }
      ​
          //...
      ​
      }
    • Test: The controller accepts data for certification

      • 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";
              }
      ​
          }
      ​
      }

4. List of single project development technologies

4.1 JSP application

  • View JSP(Java Server Page)

  • Control Servlet

  • Model JDBC(Java Database Connection)

  • The first phase of the project: JSP/Servlet+JDBC

4.2 SSM

  • View JSP

  • Control SpringMVC

  • Model MyBatis

  • The second stage project: JSP+SSM

4.3 SpringBoot

  • View Thymeleaf

  • Control SpringMVC

  • Model MyBatis/tkMapper

  • The third stage practice project: thymeleaf+SpringBoot (SSM)

Monolithic project: The front-end page of the project and the server-side code are in the same project (deployed on the same server)

 

analysis

 

VX can be added for technical exchanges or learning resources:

For the technical language learning of development technology, such as java, android, python, etc., I summarized a series of videos for 2020. I hope everyone can help each other at work, all for life, give yourself a chance, a little time, and double your salary. , Will life still be as bitter as it is now?

å¨è¿éæå ¥ å¾çæè¿ °

Guess you like

Origin blog.csdn.net/u014748504/article/details/107895406