Recently, I am working on a final work, which is to use SSM + Thymeleaf +vue+ Shiro to complete a project that has permission to log in and can add, delete, check and change user information. The following is just to realize permission authentication and login. The reason why I choose Shiro instead of Spring Security is that I have tried Security and it is really difficult to package it. Haha, so I give up and choose Shiro.

Here is a small Demo of learning Shiro:

1. First, the underlying database:

-- ----------------------------
-- Table structure for role
-- ----------------------------
CREATE TABLE `role`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Primary key of role table',
  `role_name` varchar(32) DEFAULT NULL COMMENT 'Role Name'.PRIMARY KEY (`id`)
);

-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1.'SUPER_ADMIN');
INSERT INTO `role` VALUES (2.'ADMIN');
INSERT INTO `role` VALUES (3.'USER');

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'User primary key',
  `username` varchar(32) NOT NULL COMMENT 'Username',
  `password` varchar(32) NOT NULL COMMENT 'password',
  `role_id` int(11) DEFAULT NULL COMMENT 'Foreign key associated with role role table'.PRIMARY KEY (`id`),
  CONSTRAINT `user_role_on_role_id` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`)
);

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1.'BWH_Steven'.'666666'.1);
INSERT INTO `user` VALUES (2.'admin'.'666666'.2);
INSERT INTO `user` VALUES (3.'zhangsan'.'666666'.3);

-- ----------------------------
-- Table structure for permission
-- ----------------------------
CREATE TABLE `permission`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Permission table primary key',
  `permission_name` varchar(50) NOT NULL COMMENT 'Permission name',
  `role_id` int(11) DEFAULT NULL COMMENT 'Foreign key associated with role role table'.PRIMARY KEY (`id`),
  CONSTRAINT `permission_role_on_role_id` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`)
);

-- ----------------------------
-- Records of permission
-- ----------------------------
INSERT INTO `permission` VALUES (1.'user:*'.1);
INSERT INTO `permission` VALUES (2.'user:*'.2);
INSERT INTO `permission` VALUES (3.'user:queryAll'.3);

Copy the code

2. Create a Spring Boot project and build it using Maven

Create entity classes (User, Role, Permissions) :

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
    // Set of roles corresponding to the user
    private Role role;
}
Copy the code

Role:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {
    private Integer id;
    private String roleName;


}
Copy the code

Permissions:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Permissions {
    private Integer id;
    private String permissionName;
    private Role role;
}

Copy the code

We need to know the relationship between the three entity classes, User and Role one to one, Role and Permissions one to one. Of course, we can also write it as many-to-many, which needs to change the database file and entity class.

Add dependencies to pom.xml:

Only the relevant dependent sources are given below

<dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.5.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
Copy the code

4. Integrate Mybatis with SpringBoot:

Just create a DAO layer, a service layer, and remember to add annotations:


      
<! DOCTYPEmapper PUBLIC "- / / mybatis.org//DTD Mapper / 3.0 / EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.csy.dao.UserMapper">

    <select id="queryUserByUsername" resultMap="userRoleMap">
        SELECT u.*,r.role_name FROM `user` u, `role` r
          WHERE username = #{username} AND u.role_id = r.id;
    </select>
    <! Define a resultMap that encapsulates users and roles.
    <resultMap id="userRoleMap" type="com.example.csy.entity.User">
        <id property="id" column="id"/>
        <result property="username" column="username"></result>
        <result property="password" column="password"></result>
        <! -- Configure to encapsulate the contents of UserPojo -->
        <association property="role" javaType="com.example.csy.entity.Role">
            <id property="id" column="id"></id>
            <result property="roleName" column="role_name"></result>
        </association>
    </resultMap>


    <select id="queryPermissionByUsername" resultMap="permissionRoleMap">
        SELECT p.* ,r.role_name FROM `user` u, `role` r, `permission` p
          WHERE username = #{username} AND u.role_id = r.id AND p.role_id = r.id;
    </select>
    <! Define a resultMap that encapsulates permission and roles.
    <resultMap id="permissionRoleMap" type="com.example.csy.entity.Permissions">
        <id property="id" column="id"/>
        <result property="permissionName" column="permission_name"></result>
        <! Configure the contents of the encapsulated Role -->
        <association property="role" javaType="com.example.csy.entity.Role">
            <id property="id" column="id"></id>
            <! Column is the column name of the database -->
            <result property="roleName" column="role_name"></result>
        </association>
    </resultMap>
</mapper>

Copy the code

(2) DAO layer:

@Mapper
public interface UserMapper {
    User queryUserByUsername(@Param("username") String username);

    Permissions queryPermissionByUsername(@Param("username") String username);
}
Copy the code

(3) Service layer:


@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public User queryUserByUsername(String username) {

        return userMapper.queryUserByUsername(username);
    }

    @Override
    public Permissions queryPermissionByUsername(String username) {
        returnuserMapper.queryPermissionByUsername(username); }}Copy the code

At this point, our mybatis+ SpringBoot integration is almost complete, so test it in the test class:

@SpringBootTest
class CsyApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads(a) {
        User admin = userMapper.queryUserByUsername("admin");
        System.out.println(admin.toString());
        Permissions permission = userMapper.queryPermissionByUsername("admin"); System.out.println(permission.toString()); }}Copy the code

Test result: The query result is obtained

6. Integrate Thymeleaf:

Front page:In the HTML page, we integrate Thymeleaf, use Jquery, semantic, need to guide package

Index.html code: in this case, User can only access A, Admin can access A,B, and superAdmin can access A,B, and C

<! DOCTYPEhtml>
<html lang="zh_CN"
      xmlns:th="http://www.thymeleaf.org"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Information management platform - home page</title>
    <meta
            name="viewport"
            content="width=device-width, initial-scale=1, maximum-scale=1"
    />
    <title>Home page</title>
    <! --semantic-ui-->
    <link
            href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css"
            rel="stylesheet"
    />

    <! --<link href="css/index.css" rel="stylesheet">-->
    <link th:href="@{/css/index.css}" rel="stylesheet">

    <! -- < script th: SRC = "@ {js/jquery - 3.1.1. Min. Js}" > < / script > -- >
    <script src="Js/jquery - 3.1.1. Min. Js." "></script>
</head>
<body>
<div class="ui container">
    <div class="ui secondary menu">
        <a class="active item" th:href="@{/index}">Home page</a>

        <a class="active item" th:href="@{/about}">about</a>
        <! -- Login and logout -->
        <div class="right menu">

            <! -- If not logged in -->
            <! --<div shiro:authorize="! isAuthenticated()">-->
            <div shiro:notAuthenticated="">
                <a class="item" th:href="@{/toLoginPage}">
                    <i class="address card icon"></i>The login</a>
            </div>

            <! -- If you have logged in -->
            <div shiro:authenticated="">
                <a class="item">
                    <i class="address card icon"></i>User name:<span shiro:principal></span>
                    <! <span SEC :authentication="principal. Authorities "></span>-->
                </a>
            </div>

            <div shiro:authenticated="">
                <a class="item" th:href="@{/logout}">
                    <i class="address card icon"></i>The cancellation</a>
            </div>
        </div>
    </div>

    <div class="ui stackable three column grid">
        <div class="column" shiro:hasAnyRoles="USER,ADMIN,SUPER_ADMIN"><! -- Have access to any one of the characters -->
            <div class="ui raised segments">
                <div class="ui segment">
                    <a th:href="@{/levelA/a}">L-A-a</a>
                </div>
                <div class="ui segment">
                    <a th:href="@{/levelA/b}">L-A-b</a>
                </div>
                <div class="ui segment">
                    <a th:href="@{/levelA/c}">L-A-c</a>
                </div>
            </div>
        </div>
        <div class="column" shiro:hasAnyRoles="ADMIN,SUPER_ADMIN">
            <div class="ui raised segments">
                <div class="ui segment">
                    <a th:href="@{/levelB/a}">L-B-a</a>
                </div>
                <div class="ui segment">
                    <a th:href="@{/levelB/b}">L-B-b</a>
                </div>
                <div class="ui segment">
                    <a th:href="@{/levelB/c}">L-B-c</a>
                </div>
            </div>
        </div>
        <div class="column" shiro:hasRole="SUPER_ADMIN">
            <div class="ui raised segments">
                <div class="ui segment">
                    <a th:href="@{/levelC/a}">L-C-a</a>
                </div>
                <div class="ui segment">
                    <a th:href="@{/levelC/b}">L-C-b</a>
                </div>
                <div class="ui segment">
                    <a th:href="@{/levelC/c}">L-C-c</a>
                </div>
            </div>
        </div>
        <! -- <div class="column"></div> -->
    </div>

    <div class="ui stacked segment">
        <div class="ui stackable three column grid">
            <div class="column">
                <p>The night wind blows your gray hair on your temples<br/>To heal the scars of memory<br/>Your eyes are a mixture of light and shade<br/>Twilight covers your faltering steps<br/>Went into bed to hide the painting<br/>It's you talking with your head down<br/>I still wonder how big the world is</p>
            </div>

            <div class="column">
                <p>I was also fond of childhood love words<br/>Not true or false do not struggle meaningless joke<br/>I will finally give her back my youth<br/>With the summer pop-up fingertips<br/>The heart moves away with the wind<br/>In the name of love would you still do it<br/></p>
            </div>
            <div class="column">
                <img class="ui medium circular image" src="images/001.jpg">
            </div>
        </div>

    </div>

    <div class="ui info message">
        <div class="header">The ideal is more than twenty years old</div>
        <p>BWH_Steven</p>
    </div>
</div>

</body>
</html>
Copy the code

The login. HTML code:

<! DOCTYPEhtml>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
>
<head>
    <meta charset="UTF-8">
    <title>User management System - Login</title>
    <! -- < script th: SRC = "@ {js/jquery - 3.1.1. Min. Js}" > < / script > -- >
    <script src="Js/jquery - 3.1.1. Min. Js." "></script>
    <link
            href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css"
            rel="stylesheet"
    />
</head>
<body>
<h1>User management System - Login</h1>
<div class="ui container" style="margin-top: 180px;">
    <div style="text-align: center; margin-bottom: 20px;">
        <h1 class="header">The login</h1>
    </div>

    <div class="ui three column stackable grid login-div">
        <div class="column"></div>
        <div class="column">
            <form id="login" class="ui fluid form segment" th:action="@{/login}" method="post">
                <div class="field">
                    <label class="">The user name</label>
                    <div class="ui left icon input">
                        <input type="text" name="username" placeholder=""/>
                        <i class="user icon"></i>
                        <div class="ui corner label">
                            <i class="icon asterisk"></i>
                        </div>
                    </div>
                </div>
                <div class="field">
                    <label class="">password</label>
                    <div class="ui left icon input">
                        <input type="password" name="password" placeholder=""/>
                        <i class="lock icon"></i>
                        <div class="ui corner label">
                            <i class="icon asterisk"></i>
                        </div>
                    </div>
                </div>
                <div class="inline field">
                    <div class="ui checkbox">
                        <input type="checkbox" name="terms"/>
                        <label>Remember the password</label>
                    </div>
                </div>
                <div class="inline field">
                    <input type="submit" class="ui blue submit button">
                </div>
            </form>
        </div>
        <div class="column"></div>
    </div>
</div>


</body>
</html>
Copy the code

success.html:

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>User Management System - Success</title>
</head>
<body>
<h2>Login successful</h2>
<a href="/index">Return to the home page</a>
</body>
</html>
Copy the code

7. Integrating Shiro into a project:

(1) Custom Realm:

We need to customize, authenticate and authorize:

public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserMapper userMapper;

    / * * *@MethodNameDoGetAuthorizationInfo Authorization operation *@DescriptionPermission configuration class *@Param [principalCollection]
     * @Return AuthorizationInfo
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // Get the user name information
        String username = (String) principalCollection.getPrimaryPrincipal();
        // Create a simple authorization authentication information
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // Set the role information obtained from the role table for the user
        authorizationInfo.addRole(userMapper.queryUserByUsername(username).getRole().getRoleName());
        // Set the permission information obtained from the Permission table for this user
        authorizationInfo.addStringPermission(userMapper.queryPermissionByUsername(username).getPermissionName());
        return authorizationInfo;
    }

    / * * *@MethodNameDoGetAuthenticationInfo Authentication *@DescriptionAuthentication configuration class *@Param [authenticationToken]
     * @Return AuthenticationInfo
     * @Author WangShiLin
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // Get the username based on the Token created in the receiving foreground
        String username = (String) authenticationToken.getPrincipal();

// UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
// System.out.println(userToken.getPrincipal());
// System.out.println(userToken.getUsername());
// System.out.println(userToken.getPassword());

        // Query related user information by user name (entity)
        User user = userMapper.queryUserByUsername(username);
        if(user ! =null) {
            // Save to Session, optional
            SecurityUtils.getSubject().getSession().setAttribute("user", user);
            // Shiro does the password authentication
            AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), "userRealm");
            return authenticationInfo;
        } else {
            // If null is returned, an exception is thrown
            return null; }}}Copy the code

(2) write shiroConfig:

@Configuration
public class ShiroConfig {

    // Add your own validation method to the container
    @Bean
    public UserRealm myShiroRealm(a) {
        return new UserRealm();
    }

    /** * configures the SecurityManager SecurityManager **@return* /
    @Bean
    public DefaultWebSecurityManager securityManager(a) {
        // Add custom realms
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        / / associated Realm
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }

    /** * Configure Shiro filter **@param securityManager
     * @return* /
    @Bean
    public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
        / / define shiroFactoryBean
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        / / associated securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // Customize the login page, if the login time, the request will be executed, i.e. jump to the login page
        shiroFilterFactoryBean.setLoginUrl("toLoginPage");
        // Specify a success page
        shiroFilterFactoryBean.setSuccessUrl("/success");
        // Specify an unauthorized interface
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");

        // Set a custom filter
        Map<String, Filter> filterMap = new LinkedHashMap<>();
        filterMap.put("anyRoleFilter".new MyRolesAuthorizationFilter());
        shiroFilterFactoryBean.setFilters(filterMap);

        // LinkedHashMap is ordered for sequential interceptor configuration
        Map<String, String> filterChainMap = new LinkedHashMap<>();

        // Configure the IP address that can be accessed anonymously. You can add and permit static resources based on the actual situation. Anon indicates the permit
        filterChainMap.put("/css/**"."anon");
        filterChainMap.put("/img/**"."anon");
        filterChainMap.put("/js/**"."anon");
        // Specify page release, for example, the login page allows all users to log in
        filterChainMap.put("/toLoginPage"."anon");

        // Users starting with "/user/admin" need to be authenticated. Authc indicates authentication
        filterChainMap.put("/user/admin/**"."authc");

        // page - User needs role authentication
        filterChainMap.put("/levelA/**"."anyRoleFilter[USER,ADMIN,SUPER_ADMIN]");
        filterChainMap.put("/levelB/**"."anyRoleFilter[ADMIN,SUPER_ADMIN]");
        filterChainMap.put("/levelC/**"."anyRoleFilter[SUPER_ADMIN]");

// filterChainMap.put("/levelA/**", "roles[USER]");
// filterChainMap.put("/levelB/**", "roles[ADMIN]");
// filterChainMap.put("/levelC/**", "roles[SUPER_ADMIN]");

        // / all requests under user/admin/ must be authenticated. Only the user:[*] permission can be accessed. You can also set the permission to user: XXX
        filterChainMap.put("/user/admin/**"."perms[user:*]");

        // Configure the logout filter
        filterChainMap.put("/logout"."logout");

        // Store the Map to the filter
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
        return shiroFilterFactoryBean;
    }

    /** * integrate thymeleaf *@return* /
    @Bean(name = "shiroDialect")
    public ShiroDialect shiroDialect(a){
        return new ShiroDialect();

    }



Copy the code

First we inject our custom Realm method dependency into the container

// Add your own validation method to the container
    @Bean
    public UserRealm myShiroRealm(a) {
        return new UserRealm();
    }
Copy the code

Then: SecurityManager configures the SecurityManager

/** * configures the SecurityManager SecurityManager **@return* /
    @Bean
    public DefaultWebSecurityManager securityManager(a) {
        // Add custom realms
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        / / associated Realm
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }
Copy the code

Finally, there are custom filters that control what roles those pages need to access, what resources need to be accessed by whom, and setSecurityManager, which returns a ShiroFilterFactoryBean.

Key stores URL, value stores some corresponding permissions or roles, etc. In fact, the key block is very easy to understand, for example: / CSS/and /user/admin/ respectively represent all files in the CSS folder. The request path prefix is /user/admin/ URL, and the corresponding value has certain specifications.

Roles [XXX] : [XXX] : [XXX] : [XXX] : [XXX] : You must have the permission to access a request or resource. Note: XXX is the permission parameter

(3) a custom role authentication filter MyRolesAuthorizationFilter:

Because our roles need only one role to access the mapping page, Shiro defaults to hasAllRoles, which means we need to satisfy all identities to access it, so we need to customize a hasAnyRoles and just choose one of them.

public class MyRolesAuthorizationFilter extends AuthorizationFilter {

    @SuppressWarnings({"unchecked"})
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {

        Subject subject = getSubject(request, response);
        String[] rolesArray = (String[]) mappedValue;

        if (rolesArray == null || rolesArray.length == 0) {
            //no roles specified, so nothing to check - allow access.
            return false;
        }

        List<String> roles = CollectionUtils.asList(rolesArray);
        boolean[] hasRoles = subject.hasRoles(roles);
        for (boolean hasRole : hasRoles) {
            if (hasRole) {
                return true; }}return false; }}Copy the code

(4) Finally, the controller

The Controller is the front-end controller of springMvc that receives any request and returns the corresponding page (map). First of all, we will write the mapping of all the pages,

PageController:

@Controller
public class PageController {

    @RequestMapping({"/", "index"})
    public String index(a) {
        return "index";
    }

    @RequestMapping("about")
    public String toAboutPage(a) {
        return "redirect:http://www.ideal-20.cn";
    }

    @RequestMapping("/toLoginPage")
    public String toLoginPage(a) {
        return "views/login";
    }

    @RequestMapping("/levelA/{name}")
    public String toLevelAPage(@PathVariable("name") String name) {
        return "views/L-A/" + name;
    }

    @RequestMapping("/levelB/{name}")
    public String toLevelBPage(@PathVariable("name") String name) {
        return "views/L-B/" + name;
    }

    @RequestMapping("/levelC/{name}")
    public String toLevelCPage(@PathVariable("name") String name) {
        return "views/L-C/" + name;
    }

    @RequestMapping("/unauthorized")
    public String toUnauthorizedPage(a) {
        return "views/unauthorized";
    }

    @RequestMapping("/success")
    public String toSuccessPage(a) {
        return "views/success"; }}Copy the code

UserController: The above two mappings are just tests, mainly the login method, which can create a token based on our foreground input. If the token can be authenticated, it will return a success page, otherwise it will fail.

@Controller
public class UserController {
    @RequestMapping("/user/queryAll")
    @ResponseBody
    public String queryAll(a) {
        return "This is the user/queryAll method";
    }

    @RequestMapping("/user/admin/add")
    @ResponseBody
    public String adminAdd(a) {
        return "This is the user/adminAdd method";
    }

    @RequestMapping("/login")
    public String login(String username, String password, HttpServletRequest request) {
        // Since it is obtained from the name parameter, I encapsulate it here
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);

        // Create a Token based on the foreground user name and password.
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        // Get the subject authentication principal (in this case, the user currently logged in)
        Subject subject = SecurityUtils.getSubject();
        try{
            // The authentication starts, and this jumps to the custom UserRealm
            subject.login(token);
            // Can be stored in session
            request.getSession().setAttribute("user", user);
            return "views/success";
        }catch(Exception e){
            // Catch an exception
            e.printStackTrace();
            request.getSession().setAttribute("user", user);
            request.setAttribute("errorMsg"."Dude, wrong username or password.");
            return "views/login"; }}}Copy the code

8. Final Effect:

The first is http://localhost:8080/index

Login interface:

When the form is submitted, it returns the value to the UserController Login method, which authenticates:

Now we are logged in successfully and have superAdmin permission to view A,B, and C

User John, on the other hand, can only see A

End here, this blog for reference: blog, need source please view this blog.