Spring Boot整合Shiro完成認證,權限管理,MD5+salt加密

Spring Boot整合Shiro完成認證,權限管理,MD5+salt加密

整合代碼如下

Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.junwei</groupId>
    <artifactId>springboot-shiro</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-shiro</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </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>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.28</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!--thymel對shiro的擴展標籤 整合-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

後端代碼
  1. User.java

    package com.junwei.springbootshiro.pojo;
    
    import lombok.*;
    import org.springframework.stereotype.Repository;
    
    /**
     * @Auther: wangjunwei
     * @Description: 用戶實體類
     * @Date: Created in 16:18 2019/6/8
     */
    @Setter
    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    @Repository
    public class User {
        private int id;
        private String username;
        private String password;
        private String perms;
    }
    
  2. UserMapper.java

    package com.junwei.springbootshiro.mapper;
    
    import com.junwei.springbootshiro.pojo.User;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    
    /**
     * @Auther: wangjunwei
     * @Description: 用戶mapper層
     * @Date: Created in 16:19 2019/6/8
     */
    @Mapper
    public interface UserMapper {
        User findUser(@Param("username") String username);
        User findById(@Param("id") Integer id);
    
        void toRegist(@Param("user") User user,@Param("perms") String perms);
    }
    
  3. UserMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.junwei.springbootshiro.mapper.UserMapper">
        <insert id="toRegist">
            insert into user (username, password,perms) values (#{user.username},#{user.password},
                                                                #{perms})
        </insert>
        <select id="findUser" resultType="com.junwei.springbootshiro.pojo.User">
            select id,username,password from user where username = #{username}
        </select>
        <select id="findById" resultType="com.junwei.springbootshiro.pojo.User">
            select id,username,password,perms from user where id=#{id}
        </select>
    </mapper>
    
  4. UserService.java

    package com.junwei.springbootshiro.service;
    
    import com.junwei.springbootshiro.mapper.UserMapper;
    import com.junwei.springbootshiro.pojo.User;
    import com.junwei.springbootshiro.utils.Salt;
    import org.apache.shiro.crypto.hash.Md5Hash;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    /**
     * @Auther: wangjunwei
     * @Description: 用戶業務邏輯層
     * @Date: Created in 16:21 2019/6/8
     */
    @Service
    public class UserService {
        @Autowired
        private UserMapper userMapper;
    
        public User findUser(String username) {
            return userMapper.findUser(username);
        }
    
        public User findById(Integer id) {
            return userMapper.findById(id);
        }
    
        public void toRegist(User user) {
            //密碼加鹽
            user.setPassword(new Md5Hash(user.getPassword(), Salt.addSalt).toString());
            userMapper.toRegist(user,"user:none");
        }
    }
    
  5. ShiroConfig.java

    package com.junwei.springbootshiro.shiro;
    
    import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    /**
     * @Auther: wangjunwei
     * @Description: Shiro配置類
     * @Date: Created in 10:34 2019/6/8
     */
    @Configuration
    public class ShiroConfig {
    
        /**
         * @param defaultWebSecurityManager 1
         * @return : org.apache.shiro.spring.web.ShiroFilterFactoryBean
         * @Author: wangjunwei
         * @Date: Created in 10:57 2019/6/8
         * @Description: 創建ShiroFilterFactoryBean
         */
        @Bean(name = "shiroFilterFactoryBean")
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager"
        ) DefaultWebSecurityManager defaultWebSecurityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            //設置安全管理器
            shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
            //添加shiro內置過濾器
            /*
                annon:表示可以匿名使用
                authc:表示需要認證(登錄)才能使用,沒有參數
                roles:參數可以寫多個,多個時必須加上雙引號,並且參數之間用逗號分隔
                    例如/admins/user/**=perms["user:add:*,
                    user:modify:*"],當有多個參數時必須每個參數都通過才通過,想當於isPermitedAll()方法。
                rest:根據請求的方法,相當於/admins/user/**=perms[user:method] ,其中method爲post,get,delete等。
                port:當請求的url的端口不是8081是跳轉到schemal://serverName:8081?queryString,
                其中schmal是協議http或https等,serverName是你訪問的host,
                8081是url配置裏port的端口,queryString是你訪問的url裏的?後面的參數。
                authcBasic:沒有參數表示httpBasic認證
                ssl:表示安全的url請求,協議爲https
                user:當登入操作時不做檢查
                perms:該資源必須授予權限纔可以訪問
             */
    
            Map<String, String> fMap = new LinkedHashMap<>();
            //攔截頁面
            fMap.put("/add", "authc");
            fMap.put("/update", "authc");
    
            //授權過濾器
            //注意:當前授權攔截後,shiro會自動跳轉到未授權頁面
            fMap.put("/add", "perms[user:add]");
            fMap.put("/update", "perms[user:update]");
    
            shiroFilterFactoryBean.setFilterChainDefinitionMap(fMap);
    
            //被攔截返回登錄頁面
            shiroFilterFactoryBean.setLoginUrl("/login");
            //設置未授權提示頁面
            shiroFilterFactoryBean.setUnauthorizedUrl("/permission");
            return shiroFilterFactoryBean;
        }
    
        /**
         * @param userRealm 1
         * @return : org.apache.shiro.web.mgt.DefaultWebSecurityManager
         * @Author: wangjunwei
         * @Date: Created in 17:24 2019/6/14
         * @Description: 創建SecurityManager
         */
        @Bean(name = "defaultWebSecurityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
            DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
            //關聯Realm
            defaultWebSecurityManager.setRealm(userRealm);
            return defaultWebSecurityManager;
        }
    
        /**
         * @return : com.junwei.springbootshiro.shiro.UserRealm
         * @Author: wangjunwei
         * @Date: Created in 16:55 2019/6/14
         * @Description: 創建Realm
         * 並設置加密規則
         */
        @Bean(name = "userRealm")
        public UserRealm getRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher hashedCredentialsMatcher) {
            UserRealm userRealm = new UserRealm();
            userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
            return userRealm;
        }
    
        /**
         * @return : at.pollux.thymeleaf.shiro.dialect.ShiroDialect
         * @Author: wangjunwei
         * @Date: Created in 18:00 2019/6/15
         * @Description: 配置ShiroDialect,用於thymeleaf和shiro標籤配合使用
         */
        @Bean
        public ShiroDialect getShiroDialect() {
            return new ShiroDialect();
        }
    
        /**
         * @return : org.apache.shiro.authc.credential.HashedCredentialsMatcher
         * @Author: wangjunwei
         * @Date: Created in 19:14 2019/6/15
         * @Description: 設置加密對象,加密規則
         */
        @Bean(name = "hashedCredentialsMatcher")
        public HashedCredentialsMatcher hashedCredentialsMatcher() {
            HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
            //使用md5加密算法進行加密
            hashedCredentialsMatcher.setHashAlgorithmName("md5");
            //設置散列次數:加密次數
            hashedCredentialsMatcher.setHashIterations(1);
            return hashedCredentialsMatcher;
        }
    }
    
  6. UserRealm.java

    package com.junwei.springbootshiro.shiro;
    
    import com.fasterxml.jackson.annotation.JsonTypeInfo;
    import com.junwei.springbootshiro.pojo.User;
    import com.junwei.springbootshiro.service.UserService;
    import com.junwei.springbootshiro.utils.Salt;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.subject.Subject;
    import org.apache.shiro.util.ByteSource;
    import org.springframework.beans.factory.annotation.Autowired;
    
    /**
     * @Auther: wangjunwei
     * @Description: 自定義Realm
     * @Date: Created in 16:17 2019/6/8
     */
    public class UserRealm extends AuthorizingRealm {
        @Autowired
        private UserService userService;
    
        /**
         * @param principalCollection 1
         * @return : org.apache.shiro.authz.AuthorizationInfo
         * @Author: wangjunwei
         * @Date: Created in 16:53 2019/6/14
         * @Description: 執行授權
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            //授權
            System.out.println("授權");
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            //到數據庫查詢當前登錄用戶的授權字符串
            //獲取當前登錄用戶
            Subject subject = SecurityUtils.getSubject();
            User user = (User) subject.getPrincipal();
            User result = userService.findById(user.getId());
            //授權
            simpleAuthorizationInfo.addStringPermission(result.getPerms());
            return simpleAuthorizationInfo;
        }
    
        /**
         * @param authenticationToken 1
         * @return : org.apache.shiro.authc.AuthenticationInfo
         * @Author: wangjunwei
         * @Date: Created in 16:54 2019/6/14
         * @Description: 執行認證
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            System.out.println("認證");
            //shiro判斷邏輯 判斷用戶名和密碼
            UsernamePasswordToken user = (UsernamePasswordToken) authenticationToken;
            User newUser = userService.findUser(user.getUsername());
            if (newUser == null) {
                return null;
            }
            System.out.println(user.getPassword());
            //加密加鹽認證
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(newUser,
                    newUser.getPassword(),
                    ByteSource.Util.bytes(Salt.addSalt), getName());
            return authenticationInfo;
        }
    }
    
  7. Salt.java

    package com.junwei.springbootshiro.utils;
    
    /**
     * @Auther: wangjunwei
     * @Description: 用戶加鹽
     * @Date: Created in 18:51 2019/6/15
     */
    public class Salt {
        public static final String addSalt = "regist@^$*#!";
    }
    
  8. PageController.java

    package com.junwei.springbootshiro.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    /**
     * @Auther: wangjunwei
     * @Description: 頁面跳轉controller
     * @Date: Created in 17:38 2019/6/14
     */
    @Controller
    public class PageController {
        @RequestMapping("/")
        public String toIndex(){
            return "index";
        }
    
        @RequestMapping("/{pageName}")
        public String toPage(@PathVariable String pageName){
            return pageName;
        }
    }
    
  9. UserController.java

    package com.junwei.springbootshiro.controller;
    
    import com.junwei.springbootshiro.pojo.User;
    import com.junwei.springbootshiro.service.UserService;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    /**
     * @Auther: wangjunwei
     * @Description: 用戶controller層
     * @Date: Created in 16:23 2019/6/8
     */
    @Controller
    public class UserController {
        @Autowired
        private UserService userService;
    
        @RequestMapping(value = "toLogin",method = RequestMethod.POST)
        public String toLogin(User user, Model model){
            //shiro用戶認證
            Subject subject = SecurityUtils.getSubject();
            //封裝用戶數據
            UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),
                    user.getPassword());
            try {
                subject.login(token);
                model.addAttribute("username",user.getUsername());
                return "index";
            }catch (UnknownAccountException e){
                model.addAttribute("msg","用戶名不存在");
                return "login";
            }catch (IncorrectCredentialsException e){
                model.addAttribute("msg","密碼錯誤");
                return "login";
            }
        }
    
        /**
         * @Author: wangjunwei
         * @Date: Created in 18:42 2019/6/15
         * @Description:
         * 註銷功能
         * @return : java.lang.String
         */
        @RequestMapping("logout")
        public String logout(){
            Subject subject = SecurityUtils.getSubject();
            subject.logout();
            return "index";
        }
    
        /**
         * @Author: wangjunwei
         * @Date: Created in 18:46 2019/6/15
         * @Description: 用戶註冊
         * @param user 1
         * @return : java.lang.String
         */
        @RequestMapping(value = "toRegist",method = RequestMethod.POST)
        public String toRegist(User user){
            userService.toRegist(user);
            return "index";
        }
    }
    
配置文件application.properties
#spring集成Mybatis環境 別名掃描
mybatis.type-aliases-package=com.junwei.springbootshiro.pojo
#加載Mybatis配置文件
mybatis.mapper-locations = classpath:mapper/*Mapper.xml
spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/yjlg?useUnicode=true&characterEncoding=utf-8
spring.datasource.username = root
spring.datasource.password = 123
前臺代碼
  1. index.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:shiro="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>首頁</title>
    </head>
    <body>
    <h1>首頁</h1>
    <!--驗證當前用戶是否爲“訪客”,即未登錄的用戶-->
    <p shiro:guest=""><a href="/login">請登錄</a></p>
    <p><a href="/regist">註冊</a></p>
    <p shiro:authenticated="">你好,
        <shiro:principal property="username" /><br/><a href="/logout">註銷</a></p>
    <a shiro:hasPermission="user:add" href="/add">添加</a>
    <a shiro:hasPermission="user:update" href="/update">修改</a>
    </body>
    </html>
    
  2. login.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>登錄頁面</title>
    </head>
    <body>
    <h1>登錄頁面</h1>
    <form action="/toLogin" method="post">
        <p>
            <span>用戶名:</span>
            <input type="text" name="username">
        </p>
        <p>
            <span>密碼:</span>
            <input type="password" name="password">
        </p>
        <input type="submit" value="登陸">
    </form>
    <h3 th:text="${msg}"></h3>
    </body>
    </html>
    
  3. regist.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>用戶註冊</title>
    </head>
    <body>
    <h1>用戶註冊</h1>
    <form action="/toRegist" method="post">
        <p>用戶名:<input type="text" name="username"></p>
        <p>密碼:<input type="password" name="password"></p>
        <input type="submit" value="註冊">
    </form>
    </body>
    </html>
    
  4. add.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>用戶添加</title>
    </head>
    <body>
        <h1>用戶添加頁面</h1>
    </body>
    </html>
    
  5. update.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>用戶修改</title>
    </head>
    <body>
    <h1>用戶修改頁面</h1>
    </body>
    </html>
    
  6. premission.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>未授權提示頁面</title>
    </head>
    <body>
    <h1>爲授權提示頁面</h1>
    </body>
    </html>
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章