2.springboot整合Shrio 02

1.pom.xml
和之前一樣 只是多加了阿里連接池
com.alibaba
druid

<!--thymeleaf-->
<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>
<!--shiro支持-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>
<!--持久層框架mybatis和mysql驅動8.0.9-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<!--阿里連接池-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.14</version>
</dependency>
<!--插件簡化代碼-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

2.application.properties

pring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai
#緩存關閉
spring.thymeleaf.cache=false
#mapper包掃描
mybatis.mapper-locations=classpath:mapper/*.xml 
#實體類別名
mybatis.type-aliases-package=com.shiro.pojo
#駝峯命名開啓
mybatis.configuration.map-underscore-to-camel-case=true
#session
server.servlet.session.timeout=5
spring.mvc.hiddenmethod.filter.enabled=true
spring.profiles.active=pro

application-pro.properties文件專門放阿里連接池配置
#連接池配置阿里巴巴的

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

3.sql

#創建數據庫 shiro
DROP DATABASE IF EXISTS shiro;
CREATE DATABASE IF NOT EXISTS shiro;
#切換數據庫
USE shiro;
#刪
    
DROP TABLE IF EXISTS USER;
DROP TABLE IF EXISTS role;
DROP TABLE IF EXISTS permission;
DROP TABLE IF EXISTS user_role;
DROP TABLE IF EXISTS role_permission;
#創建
CREATE TABLE USER (
  id BIGINT AUTO_INCREMENT,
  NAME VARCHAR(100),
  PASSWORD VARCHAR(100),
  salt VARCHAR(100),
  CONSTRAINT pk_users PRIMARY KEY(id)
) CHARSET=utf8 ENGINE=INNODB;
    
CREATE TABLE role (
  id BIGINT AUTO_INCREMENT,
  NAME VARCHAR(100),
  desc_ VARCHAR(100),
  CONSTRAINT pk_roles PRIMARY KEY(id)
) CHARSET=utf8 ENGINE=INNODB;
    
CREATE TABLE permission (
  id BIGINT AUTO_INCREMENT,
  NAME VARCHAR(100),
  desc_ VARCHAR(100),
  url VARCHAR(100),
  CONSTRAINT pk_permissions PRIMARY KEY(id)
) CHARSET=utf8 ENGINE=INNODB;
    
CREATE TABLE user_role (
  id BIGINT AUTO_INCREMENT,
  uid BIGINT,
  rid BIGINT,
  CONSTRAINT pk_users_roles PRIMARY KEY(id)
) CHARSET=utf8 ENGINE=INNODB;
    
CREATE TABLE role_permission (
  id BIGINT AUTO_INCREMENT,
  rid BIGINT,
  pid BIGINT,
  CONSTRAINT pk_roles_permissions PRIMARY KEY(id)
) CHARSET=utf8 ENGINE=INNODB;
 #插入
INSERT INTO `permission` VALUES (1,'addProduct','增加產品','/addProduct');
INSERT INTO `permission` VALUES (2,'deleteProduct','刪除產品','/deleteProduct');
INSERT INTO `permission` VALUES (3,'editeProduct','編輯產品','/editeProduct');
INSERT INTO `permission` VALUES (4,'updateProduct','修改產品','/updateProduct');
INSERT INTO `permission` VALUES (5,'listProduct','查看產品','/listProduct');
INSERT INTO `permission` VALUES (6,'addOrder','增加訂單','/addOrder');
INSERT INTO `permission` VALUES (7,'deleteOrder','刪除訂單','/deleteOrder');
INSERT INTO `permission` VALUES (8,'editeOrder','編輯訂單','/editeOrder');
INSERT INTO `permission` VALUES (9,'updateOrder','修改訂單','/updateOrder');
INSERT INTO `permission` VALUES (10,'listOrder','查看訂單','/listOrder');
INSERT INTO `role` VALUES (1,'admin','超級管理員');
INSERT INTO `role` VALUES (2,'productManager','產品管理員');
INSERT INTO `role` VALUES (3,'orderManager','訂單管理員');
INSERT INTO `role_permission` VALUES (1,1,1);
INSERT INTO `role_permission` VALUES (2,1,2);
INSERT INTO `role_permission` VALUES (3,1,3);
INSERT INTO `role_permission` VALUES (4,1,4);
INSERT INTO `role_permission` VALUES (5,1,5);
INSERT INTO `role_permission` VALUES (6,1,6);
INSERT INTO `role_permission` VALUES (7,1,7);
INSERT INTO `role_permission` VALUES (8,1,8);
INSERT INTO `role_permission` VALUES (9,1,9);
INSERT INTO `role_permission` VALUES (10,1,10);
INSERT INTO `role_permission` VALUES (11,2,1);
INSERT INTO `role_permission` VALUES (12,2,2);
INSERT INTO `role_permission` VALUES (13,2,3);
INSERT INTO `role_permission` VALUES (14,2,4);
INSERT INTO `role_permission` VALUES (15,2,5);
INSERT INTO `role_permission` VALUES (50,3,10);
INSERT INTO `role_permission` VALUES (51,3,9);
INSERT INTO `role_permission` VALUES (52,3,8);
INSERT INTO `role_permission` VALUES (53,3,7);
INSERT INTO `role_permission` VALUES (54,3,6);
INSERT INTO `role_permission` VALUES (55,3,1);
INSERT INTO `role_permission` VALUES (56,5,11);
INSERT INTO `user` VALUES (1,'zhang3','a7d59dfc5332749cb801f86a24f5f590','e5ykFiNwShfCXvBRPr3wXg==');
INSERT INTO `user` VALUES (2,'li4','43e28304197b9216e45ab1ce8dac831b','jPz19y7arvYIGhuUjsb6sQ==');
INSERT INTO `user_role` VALUES (43,2,2);
INSERT INTO `user_role` VALUES (45,1,1);
#getPassword 方法: 查密碼
SELECT PASSWORD FROM USER WHERE NAME ='li4'


# listRoles 方法: 根據用戶名查詢此用戶有哪些角色,這是3張表的關聯
SELECT r.name FROM USER u 
LEFT JOIN user_role ur ON u.id = ur.uid 
LEFT JOIN Role r ON r.id = ur.rid 
WHERE u.name = 'zhang3';

#listPermissions 方法:根據用戶名查詢此用戶有哪些權限,這是5張表的關聯
SELECT p.name FROM USER u 
	LEFT JOIN user_role ru ON u.id = ru.uid 
	LEFT JOIN role r ON r.id = ru.rid 
	LEFT JOIN role_permission rp ON r.id = rp.rid 
	LEFT JOIN permission p ON p.id = rp.pid 
	WHERE u.name ='li4'

4.通過idea連接數據庫快速創建pojo類,導包名修改一下即可
5.UserDao 和UserService(省略)

@Repository
@Mapper
public interface UserDao {
    //根據用戶名查密碼
    @Select ("SELECT PASSWORD FROM USER WHERE NAME =#{name}")
    String  getPwdByName(String name);

    //三表查詢,根據用戶名查詢角色
    List<String> listRoles(String name);

    //根據用戶名查詢 權限 五表查詢
    List<String>  listPermissions(String name);

}
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserDao userDao;

    @Override
    public String getPwdByName(String name) {
        return userDao.getPwdByName (name);
    }

    @Override
    public List<String> listRoles(String name) {
        return userDao.listRoles (name);
    }

    @Override
    public List<String> listPermissions(String name) {
        return userDao.listPermissions (name);
    }
}

6.接下來是修改認證邏輯:

/*授權和認證邏*/
public class CustomRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println ("執行授權邏輯");


        SimpleAuthorizationInfo simpleInfo = new SimpleAuthorizationInfo ( );
        //獲取登錄用戶名
        String name = (String) principalCollection.getPrimaryPrincipal ( );
        //之後在數據庫查詢他是什麼角色 什麼權限一一添加他們
        System.out.println ("查詢角色和權限:" + name);
        List<String> listRoles = userService.listRoles (name);
        // simpleInfo.addRoles (listRoles);直接添加多個角色或者forench添加
        for (String role : listRoles) {
            simpleInfo.addRole (role);
        }
        //添加角色下的權限 比如crud
        List<String> listPermissions = userService.listPermissions (name);
        simpleInfo.addStringPermissions (listPermissions);
        //設置好權限返回
        return simpleInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //加這一步的目的是在Post請求的時候會先進認證,然後在到請求
        if (null == authenticationToken.getPrincipal ( )) {
            return null;
        }
        System.out.println ("執行認證邏輯");

        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        //獲取用戶登陸的名
        String name = token.getUsername ( );
        String pwd = userService.getPwdByName (name);
        if (null == pwd) {
            //用戶名不存在
            return null;//拋出一個空的對象 拋出異常UnknowAccountException
        }


        //這裏驗證authenticationToken和simpleAuthenticationInfo的信息
        return new SimpleAuthenticationInfo (name, pwd, getName ( ));
    }
}

7.Shiro配置:

/*常用的過濾器
* anon:無認證
* authc:必須認證 登陸即可
* user: 使用記住我可以直接訪問
* perms: 必須有資源權限 比如crud
* roles: 必須有角色權限
* */
@Configuration
public class ShiroConfig {
    /**
     * 創建自定義配置的Realm
     */
    @Bean
    CustomRealm myRealm() {
        return new CustomRealm ( );
    }

    /**
     * 創建DefaultWebSecurityManager管理器,使它管理自定義的Realm
     */
    @Bean
    DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager ( );
        manager.setRealm (myRealm ( ));
        return manager;
    }

    /**
     *創建shiroFilterFactoryBean
     * 關聯一個securityManager ( )管理器
     */
    @Bean
    ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean ( );
        bean.setSecurityManager (securityManager ( ));
        //登陸頁
        bean.setLoginUrl ("/login");
        //登陸成功後界面
        bean.setSuccessUrl ("/index");
        //未授權跳轉到
        bean.setUnauthorizedUrl ("/tip");
        Map<String, String> map = new LinkedHashMap<> ( );
        //anon是把限制權限改爲無限制
        //map.put ("/index", "anon");
        //authc 登陸後可以訪問
       // map.put ("/**", "authc");
        map.put ("/add", "authc");
        //權限必須有addProduct纔可以訪問
        map.put ("/update","perms[addProduct]");
        //角色是admin 纔可以訪問超級管理員界面
        map.put ("/admin","roles[admin]");
        bean.setFilterChainDefinitionMap (map);
        return bean;
    }


}

8.controller

@Controller
public class LoginController {
    //表單提交,處理後返回首頁
    @PostMapping("/tologin")
    String tologin(String name, String password, Model model) {
        //處理邏輯
        /**使用Shiro編寫認證操作*/
        //1.獲取Subject
        Subject subject = SecurityUtils.getSubject ( );
        //2.封裝用戶數據
        UsernamePasswordToken token = new UsernamePasswordToken (name, password);
        //執行登陸方法

        try {
            subject.login (token);
            //登陸信息會交給Realm去執行認證邏輯,比如去數據庫對比用戶,密碼
            //然後會設置角色,權限

        } catch (UnknownAccountException e) {
            model.addAttribute ("msg", "用戶名不存在");
            return "/login";
        } catch (IncorrectCredentialsException e) {
            model.addAttribute ("msg", "密碼錯誤");
            return "/login";
        }
        //這裏的請求不能返回"/index"這是返回index.html了 沒有經過mvc攔截到
        // 必須使用"redirect:/index" 或者"forward:/index"
        //catch塊可以跳轉是因爲我的頁面就叫login.html 請求也是/login
        return "redirect:/index";
    }
    @RequestMapping("/tip")
    @ResponseBody
    String  tip(){

        return "抱歉,您沒有權限訪問該頁面!";
    }

}
@Controller
public class UserController {
    @GetMapping("/login")
    String login() {
        return "login";
    }

    @RequestMapping("/index")
    String test() {
        return "test";
    }

    @GetMapping("/add")
    String add() {
        return "add";
    }

    @GetMapping("/update")
    String update() {
        return "update";
    }

    @ResponseBody
    @GetMapping("/admin")
    String admin() {
        return "歡迎您超級管理者!";
    }
}

路徑是這樣的先請求/index 返回到首頁展示三鏈接(/add,/update,/admin)
點擊後後被攔截到登陸頁/login 賬號密碼post提交後到/tologin 數據庫查詢無誤後返回首頁,有誤返回登陸頁
這時候可以訪問三鏈接 有權限放行 沒有則跳轉到提示信息/tip
9.html
add.html

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

update.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用戶更改的頁面</title>
</head>
<body>
        用戶更改
</body>
</html>

test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用戶的測試頁面</title>
</head>
<body>
<h2 th:text="${name}"></h2>
<hr/>
<p> 進入用戶添加功能:<a href="/add">用戶添加,登陸就可以操作</a></p>
<p>進入用戶更新功能:<a href="/update">用戶更新,擁有addProduct權限可以操作</a></p>
<p><a href="/admin">超級管理admin角色界面</a></p>
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陸頁面</title>
</head>
<body>
<h3 th:text="${msg}" style="color: red"></h3>
<form method="post" action="/tologin">
    用戶名:<input type="text" name="name"/> <br/>
    密碼:<input type="password" name="password"><br/>
    <input type="submit" value="登陸">
</form>
</body>
</html>

10.測試
有兩個用戶 zhang3爲admin 角色 有許多權限可以查sql li4是個經理 沒有admin權限
10.1.亂輸一個
10.2.登陸張三,然後訪問三界面:全部可以
10.3.換成li4登陸.在訪問:
/admin返回了302狀態 然後發給了/tip
**補上mapper.xml:**可以通過選中dao名按住ALT+enter快速創建映射,再選擇方法名創建…

	<?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.shiro.dao.UserDao">

    <select id="listRoles" resultType="java.lang.String">

        SELECT r.name FROM USER u
            LEFT JOIN user_role ur ON u.id = ur.uid
            LEFT JOIN Role r ON r.id = ur.rid
            WHERE u.name =#{name}


    </select>
    <select id="listPermissions" resultType="java.lang.String">
        SELECT p.name FROM USER u
	        LEFT JOIN user_role ru ON u.id = ru.uid
	        LEFT JOIN role r ON r.id = ru.rid
	        LEFT JOIN role_permission rp ON r.id = rp.rid
	        LEFT JOIN permission p ON p.id = rp.pid
	        WHERE u.name =#{name}
    </select>
</mapper>

有錯誤的話歡迎指正!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章