shiro - integrated web

The previous two sections introduced how identity and authority authentication is performed in Shiro, but only for Shiro authentication. In simpler terms, the .ini configuration file is used, and an example of using jdbc realm is also given. This article Mainly to summarize how Shiro integrates the web, that is, how it is used in web projects.

This article does not use a web framework, such as springmvc or struts2, uses the original servlet, and uses the .ini configuration file, which is designed to be simple and rude to illustrate the problem.

Let's summarize the steps for Shiro to integrate the web.

1. Configuration

1.1 web.xml configuration

  If Shiro wants to be integrated into the web, you first need to configure Shiro's listeners and filters in web.xml, as follows:

<!-- Add shiro support-->
 <listener>
   <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
 </listener>

 <filter>
   <filter-name>ShiroFilter</filter-name>
   <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
   <init-param>
    <param-name>configPath</param-name>
    <param-value>/WEB-INF/shiro.ini</param-value>
   </init-param>
 </filter>

 <filter-mapping>
   <filter-name>ShiroFilter</filter-name>
   <url-pattern>/*</url-pattern>
 </filter-mapping>

 As can be seen from the above configuration, the path to define the Shiro configuration file is in the /WEE-INF/shiro.ini file, and Shiro's filter will intercept all requests. The other configuration in web.xml is the servlet mapping configuration. Different servlets correspond to different request urls, as follows:

<servlet>
   <servlet-name>LoginServlet</servlet-name>
   <servlet-class>demo.shiro.servlet.LoginServlet</servlet-class>
 </servlet>  
 <servlet-mapping>
  <servlet-name>LoginServlet</servlet-name>
  <url-pattern>/login</url-pattern>
</servlet-mapping>

 <servlet>
   <servlet-name>AdminServlet</servlet-name>
   <servlet-class>demo.shiro.servlet.AdminServlet</servlet-class>
 </servlet>
 <servlet-mapping>
  <servlet-name>AdminServlet</servlet-name>
  <url-pattern>/admin</url-pattern>
</servlet-mapping>

<servlet>
  <servlet-name>TeacherRoleServlet</servlet-name>
  <servlet-class>demo.shiro.servlet.TeacherRoleServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>TeacherRoleServlet</servlet-name>
  <url-pattern>/student</url-pattern>
</servlet-mapping>
<servlet-mapping>

<servlet>
  <servlet-name>LogoutServlet</servlet-name>
  <servlet-class>demo.shiro.servlet.LogoutServlet</servlet-class>
</servlet>
<servlet-name>LogoutServlet</servlet-name>
  <url-pattern>/logout</url-pattern>
</servlet-mapping>

<servlet>
  <servlet-name>TeacherPermsServlet</servlet-name>
  <servlet-class>demo.shiro.servlet.TeacherPermsServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>TeacherPermsServlet</servlet-name>
  <url-pattern>/teacher</url-pattern>
</servlet-mapping>

1.2 pom.xml configuration

  The relevant jar needs to be introduced in the pom file

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>demo.shiro</groupId>
  <artifactId>ShiroWeb</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
    <!-- shiro core package-->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.2.5</version>
    </dependency>
    <!-- Add shiro web support-->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-web</artifactId>
        <version>1.2.5</version>
    </dependency>

    <!-- Add sevlet support-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>
    <!-- Add jsp support-->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.1</version>
    </dependency>
    <!-- Add jstl support-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    <!-- Add log4j log -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>ShiroWeb</finalName>
  </build>
</project>

2. Shiro's built-in filters (Default Filters)

  When running a web application, Shiro will create some useful built-in filter instances and automatically use them in the [main] section. We can configure them manually, just like beans in spring, and reference them in our own defined url. The filters built into Shiro are the following:

 

 

 

 These built-in filters are used in this way. Generally, a request url corresponds to a filter name first. Since the filter corresponds to a class, there will be an attribute in this class. This attribute is specified when the verification fails. Jump to that url, so configure this property to the url you want to request after the verification fails. Here I cite a few of them (anonymous, authentication, permission verification, permission verification) to illustrate how to use them, others are similar.

3. Shiro's configuration file

  For the verifications I mentioned above, first write the shiro.ini file:

 

[main]
#Define the request url mapping after authentication failure, loginUrl is an attribute in the authentication filter
authc.loginUrl = / login
#Define the request url mapping after role authentication fails, unauthorizedUrl is an attribute in the role authentication filter
roles.unauthorizedUrl=/unauthorized.jsp
#Define request url mapping after role authentication fails, unauthorizedUrl is an attribute in the role authentication filter
perms.unauthorizedUrl=/unauthorized.jsp

#define several users and roles
[users]
csdn1=123,admin,teacher
csdn2=123,teacher
csdn3=123,student
csdn4=123

#Define permissions for different roles
[roles]
admin=user:*,student:*
teacher=student:*

#Define what verification the requested address needs to do
[urls]
#When requesting login, no permission is required, just as a visitor (anon)
/login=anon
#When requesting /admin, authentication is required (authc)
/ admin = authc
#When requesting /student, role authentication is required, and it must be a user with teacher role.
/student=roles[teacher]
#When requesting /teacher, permission authentication is required, and it must be a user with the role of user:create permission.
/teacher=perms["user:create"]

 Let me briefly explain this configuration, such as authc.loginUrl=/login defined in [main], authc is a built-in filter, which corresponds to the org.apache.shiro.web.filter.authc.AnonymousFilter class, and this class has A loginUrl attribute indicates the url mapping to be requested after the verification fails. This url mapping corresponds to a specific servlet. After reading this, you can compare it with the servlet configuration above. The same is true for roles.unauthorizedUrl, except that the verification fails to directly request a specific jsp page. 

 

  [users] is the subject authentication subject, so I won't go into details. [urls] defines which requests need to be intercepted and what verification should be done. For example, the url mapping request of /login is not intercepted because it is a login. If the url mapping of /admin is requested, identity authentication is required. If the url mapping of /student is requested, role authentication must be performed, and it must be the teacher role. Permission authentication is required for url mapping, and only users with user:create permissions can pass the authentication.

 

4. Test procedure

  Next, test the above certifications one by one.

4.1 Test authc authentication

  To test authc, there must be a /admin request, plus the above servlet configuration, we can first complete LoginServlet and AdminServlet.

//LoginServlet.java
public class LoginServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("login doGet");
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        Subject currentUser = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            currentUser.login(token);
            System.out.println("Authentication succeeded");
            request.getSession().setAttribute("username", username);
            request.getRequestDispatcher("/success.jsp").forward(request, response);
        } catch (AuthenticationException e) {
            e.printStackTrace ();
            System.out.println("Authentication failed");
            request.getRequestDispatcher("/login.jsp").forward(request, response);
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        doGet(request, response);
    }
}

 If the authentication is successful, it will jump to the success.jsp page. If the authentication fails, it will go to the login page, let the user log in first, and take a look at success.jsp and login.jsp

<form action="${pageContext.request.contextPath }/login" method="post">
    username:<input type="text" name="username"/><br>
    password:<input type="password" name="password"/><br>
    <input type="submit" value="登陆">
</form>

 Because the login submission request is /login, and /login=anon means anonymous authentication, so the authentication will not be intercepted, but directly enter the LoginServlet to execute the authentication code written by ourselves. The following is success.jsp, very simple.

<body>
     Welcome ${username }
     <a href="${pageContext.request.contextPath }/logout">退出</a>
</body>

 By the way, I wrote LogoutServlet:

public class LogoutServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.getSession().invalidate(); //Invalidate the session directly
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        doGet(request, response);
    }
}

 Then there is the /admin request, the request is AdminServlet.jsp, if the authentication is successful, it will enter the servlet:

public class AdminServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("admin doGet");
        request.getRequestDispatcher("/success.jsp").forward(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        doGet(request, response);
    }
}

 After writing, open tomcat and visit in the browser: http://localhost:8080/ShiroWeb/admin to request AdminServlet.java, Shiro will authenticate according to the configuration (/admin=authc), but at this time it must be It is the authentication failure, so according to the configuration (authc.loginUrl=/login) to request LoginServlet.java, Shiro will not verify, because /login=anon, but the LoginServlet.java program will verify, we wrote it ourselves. Because there is no user name and password, the authentication fails, and it will jump to the login.jsp login page. After entering the user name and password, request /login again. At this time, enter LoginServlet.java again, the authentication is successful, and enter the success.jsp page. 

  Because there is a default cache time of 30 minutes in Shiro, when we visit http://localhost:8080/ShiroWeb/admin again, we can access AdminServlet.java, and we can break the point verification in it. Then drop to success.jsp. This is the process of authentication.

4.2 Test roles authentication

  According to the configuration file, we need to request /student to trigger roles role authentication, so according to the servlet mapping, we complete the TeacherRoleServlet.java code.

 

public class TeacherRoleServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("role deget");
        Subject currentUser = SecurityUtils.getSubject();
        //其实是不用判断了,因为只要进来了,肯定角色是对的,否则进不来
        //判断当前用户是否具有teacher角色
        if(currentUser.hasRole("teacher")) {
            request.getRequestDispatcher("/success.jsp").forward(request, response);
        } else {            
            request.getRequestDispatcher("/unauthorized.jsp").forward(request, response);
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        doGet(request, response);
    }
}

 

上面程序的注释中也提到了,其实可以不用再认证了,因为进入该servlet之前,Shiro已经帮我们认证了,只有认证成功才会进入到该servlet,否则会根据配置(roles.unauthorizedUrl=/unauthorized.jsp)会直接跳转到unauthorized.jsp页面显示。

 

<body>
     认证未通过,或者权限不足
     <a href="${pageContext.request.contextPath }/logout">退出</a>
</body>

 

然后我们在浏览器中输入http://localhost:8080/ShiroWeb/student来请求TeacherRoleServlet,这里需要注意的是,刚刚测试过后需要点击退出,否则还是当前用户,会影响这次的测试。在测试角色认证的时候,它会先进行身份认证,再进行角色认证。也就是说,Shiro会先跳转到登陆页面让我们登陆,我们可以尝试两个不同的用户csdn1(有teacher角色)和csdn3(没有teacher角色)来测试。

4.2 测试perms权限认证

  和上面一样,先写TeacherPermsServlet.java:

 

public class TeacherPermsServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("perms doget");
        Subject currentUser = SecurityUtils.getSubject();
        // 其实是不用判断了,因为只要进来了,肯定角色是对的,否则进不来
        // 判断当前用户是否具有teacher角色
        if (currentUser.isPermitted("user:create")) {
            request.getRequestDispatcher("/success.jsp").forward(request,
                    response);
        } else {
            request.getRequestDispatcher("/unauthorized.jsp").forward(request,
                    response);
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        doGet(request, response);
    }
}

 然后我们在浏览器中输入http://localhost:8080/ShiroWeb/teacher来请求TeacherPermsServlet ,这里同样需要注意的是,刚刚测试过后需要点击退出,否则还是当前用户,会影响这次的测试。在测试权限认证的时候,它同样会先进行身份认证,再进行权限认证。也就是说,Shiro会先跳转到登陆页面让我们登陆,我们可以尝试两个不同的用户csdn1(有admin角色,从而有user:create权限)和csdn3(没有admin角色,从而没有user:create权限)来测试。

5. url匹配方式

  这里提一下Shiro在集成web的时候,url可以不用向上面那样写的很死,它可以匹配的,比如:

 

/admin?=authc,表示可以请求以admin开头的字符串,如xxx/adminfefe,但无法匹配多个,即xxx/admindf/admin是不行的 
/admin*=authc表示可以匹配零个或者多个字符,如/admin,/admin1,/admin123,但是不能匹配/admin/abc这种 
/admin/**=authc表示可以匹配零个或者多个路径,如/admin,/admin/ad/adfdf等。 
/admin*/**=authc这个就不多说了,结合上面两个就知道了。

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326092232&siteId=291194637