【原】無腦操做:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf實現基礎認證權限

開發環境搭建參見《【原】無腦操做:IDEA + maven + SpringBoot + JPA + Thymeleaf實現CRUD及分頁html

需求:java

① 除了登陸頁面,在地址欄直接訪問其餘URL,均跳轉至登陸頁面mysql

② 登陸涉及賬號和密碼,賬號錯誤提示賬號錯誤,密碼錯誤提示密碼錯誤web

③ 登陸成功跳轉至首頁,首頁顯示登陸者賬號信息,並有註銷賬號功能,點擊註銷退出系統spring

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------sql

分析:數據庫

典型的運用認證權限的需求,考慮使用Shiro。瞭解一下Shiro框架,Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、受權、密碼和會話管理。apache


關鍵詞彙:json

① Subject:安全術語,本意是「當前的操做用戶」。安全

                 在安全領域,術語「Subject」能夠是人,也能夠是第三方進程、後臺賬戶(Daemon Account)、定時做業(Corn Job)或其餘相似事物。

                 它僅僅意味着「當前跟軟件交互的東西」。但考慮到大多數目的和用途,你能夠把它認爲是Shiro的「用戶」概念。

                 在程序中能輕易得到Subject,容許在任何須要的地方進行安全操做。

                 每一個Subject對象都必須與一個SecurityManager進行綁定,訪問Subject對象其實都是在與SecurityManager裏的特定Subject進行交互。

② SecurityManager:安全管理器。

                               Subject表明了當前用戶的安全操做,SecurityManager則管理全部用戶的安全操做。

③ Realm:域,Shiro從Realm獲取安全數據(如用戶、角色、權限),

                即SecurityManager要驗證用戶身份,須要從Realm獲取相應用戶進行比較以肯定用戶身份是否合法;

                也就是說須要從Realm獲得用戶相應的角色/權限進行驗證用戶是否能進行操做;能夠把Realm當作DataSource,安全數據源。

④ authentication:認證(發音:[ɔ:ˌθentɪ'keɪʃn])

⑤ authorization:受權(發音:[ˌɔ:θərəˈzeɪʃn])

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

0、數據庫建表init.sql

 1 DROP TABLE sys_user;
 2 
 3 CREATE TABLE sys_user
 4 (
 5     userid INT AUTO_INCREMENT PRIMARY KEY COMMENT '用戶編號',
 6     username VARCHAR(10) NOT NULL COMMENT '用戶名稱',
 7     `password` VARCHAR(10) NOT NULL COMMENT '用戶密碼'
 8 );
 9 
10 INSERT INTO sys_user VALUES(NULL, 'admin', '123'), (NULL, 'test', '456');
11 
12 SELECT * FROM sys_user;

 

一、編寫項目對象模型文件pom.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6 
 7     <groupId>cn.temptation</groupId>
 8     <artifactId>studyShiro</artifactId>
 9     <version>1.0-SNAPSHOT</version>
10 
11     <parent>
12         <groupId>org.springframework.boot</groupId>
13         <artifactId>spring-boot-starter-parent</artifactId>
14         <version>2.0.4.RELEASE</version>
15     </parent>
16 
17     <dependencies>
18         <!-- web -->
19         <dependency>
20             <groupId>org.springframework.boot</groupId>
21             <artifactId>spring-boot-starter-web</artifactId>
22         </dependency>
23         <!-- thymeleaf -->
24         <dependency>
25             <groupId>org.springframework.boot</groupId>
26             <artifactId>spring-boot-starter-thymeleaf</artifactId>
27         </dependency>
28         <!-- spring data jpa -->
29         <dependency>
30             <groupId>org.springframework.boot</groupId>
31             <artifactId>spring-boot-starter-data-jpa</artifactId>
32         </dependency>
33         <!-- mariadb -->
34         <dependency>
35             <groupId>org.mariadb.jdbc</groupId>
36             <artifactId>mariadb-java-client</artifactId>
37             <version>2.2.5</version>
38         </dependency>
39         <!-- shiro -->
40         <dependency>
41             <groupId>org.apache.shiro</groupId>
42             <artifactId>shiro-spring</artifactId>
43             <version>1.4.0</version>
44         </dependency>
45         <!-- 熱啓動 -->
46         <dependency>
47             <groupId>org.springframework.boot</groupId>
48             <artifactId>spring-boot-devtools</artifactId>
49             <optional>true</optional>
50         </dependency>
51     </dependencies>
52 </project>

 

二、編寫項目配置文件application.properties

 1 # 數據庫訪問配置
 2 # 對應MariaDB驅動
 3 spring.datasource.driverClassName=org.mariadb.jdbc.Driver
 4 # 數據源配置
 5 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
 6 spring.datasource.username=root
 7 spring.datasource.password=sa
 8 # 配置Springboot默認支持的Hikari數據庫鏈接池
 9 spring.datasource.type=com.zaxxer.hikari.HikariDataSource
10 spring.datasource.hikari.minimum-idle=5
11 spring.datasource.hikari.maximum-pool-size=15
12 spring.datasource.hikari.auto-commit=true
13 spring.datasource.hikari.idle-timeout=30000
14 spring.datasource.hikari.pool-name=DatebookHikariCP
15 spring.datasource.hikari.max-lifetime=1800000
16 spring.datasource.hikari.connection-timeout=30000
17 spring.datasource.hikari.connection-test-query=SELECT 1
18 # Spring Data JPA配置
19 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
20 spring.jpa.properties.hibernate.hbm2ddl.auto=update
21 spring.jpa.show-sql=true
22 spring.jpa.properties.hibernate.format_sql=true
23 # 格式化輸出的json字符串
24 spring.jackson.serialization.indent_output=true
25 # 設置控制檯彩色打印
26 spring.output.ansi.enabled=ALWAYS

 

三、編寫項目啓動類Application.java

 1 package cn.temptation;
 2 
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 
 6 @SpringBootApplication
 7 public class Application {
 8     public static void main(String[] args) {
 9         // SpringBoot項目啓動
10         SpringApplication.run(Application.class, args);
11     }
12 }

 

四、編寫登陸頁面login.html 和 首頁頁面index.html

登陸頁面:login.html

 1 <!DOCTYPE html>
 2 <html xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>系統登陸</title>
 6 </head>
 7 <body>
 8 <div th:text="${msg}" style="color: red"></div>
 9 <form action="doLogin" method="post">
10 賬號:<input type="text" id="txtUsername" name="username" /><br/>
11 密碼:<input type="password" id="txtPassword" name="password" /><br/><br/>
12 <input type="submit" value="提交" />&nbsp;<input type="reset" value="重置" />
13 </form>
14 </body>
15 </html>

首頁頁面:index.html

 1 <!DOCTYPE html>
 2 <html xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>系統首頁</title>
 6 </head>
 7 <body>
 8 <div th:text="${'歡迎您,' + currentuser}" style="color: red;float: left;"></div>
 9 <div style="color: red;float: right;"><a href="doLogout">註銷</a></div>
10 </body>
11 </html>

 

五、編寫Shiro框架用配置類ShiroConfig.java 和 自定義Realm類MyRealm.java

配置類ShiroConfig.java

 1 package cn.temptation.shiro;
 2 
 3 import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
 4 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
 5 import org.springframework.beans.factory.annotation.Qualifier;
 6 import org.springframework.context.annotation.Bean;
 7 import org.springframework.context.annotation.Configuration;
 8 
 9 import java.util.LinkedHashMap;
10 import java.util.Map;
11 
12 /**
13  * Shiro配置類
14  */
15 @Configuration
16 public class ShiroConfig {
17     // 一、建立ShiroFilterFactoryBean
18     @Bean
19     public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
20         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
21         // 設置安全管理器
22         shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
23 
24         // 設置登陸跳轉頁面
25         shiroFilterFactoryBean.setLoginUrl("/login");
26 
27         /**
28          * Shiro內置過濾器:實現權限相關的攔截
29          *      經常使用過濾器:
30          *          anon(認證用):無需認證(登陸)便可訪問
31          *          authc(認證用):必須認證纔可訪問
32          *          user(少用):使用rememberMe功能能夠訪問
33          *          perms(受權用):必須獲得資源權限纔可訪問
34          *          role(受權用):必須獲得角色權限纔可訪問
35          */
36         Map<String, String> filterMap = new LinkedHashMap<>();
37 
38         // 放行登陸請求
39         filterMap.put("/doLogin", "anon");
40 
41         // 配置退出過濾器,退出代碼Shiro已經實現
42         filterMap.put("/logout", "logout");
43 
44         // 過濾鏈定義,從上向下順序執行,通常將/*放在最下邊
45         filterMap.put("/*", "authc");
46 
47         shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
48 
49         return shiroFilterFactoryBean;
50     }
51 
52     // 二、建立DefaultWebSecurityManager
53     @Bean(name = "securityManager")
54     public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("myRealm") MyRealm myRealm) {
55         DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
56 
57         // 關聯Realm
58         defaultWebSecurityManager.setRealm(myRealm);
59 
60         return defaultWebSecurityManager;
61     }
62 
63     // 三、建立Realm
64     @Bean(name = "myRealm")
65     public MyRealm getRealm() {
66         return new MyRealm();
67     }
68 }

自定義Realm類MyRealm.java

 1 package cn.temptation.shiro;
 2 
 3 import cn.temptation.dao.UserDao;
 4 import cn.temptation.domain.User;
 5 import org.apache.shiro.authc.*;
 6 import org.apache.shiro.authz.AuthorizationInfo;
 7 import org.apache.shiro.realm.AuthorizingRealm;
 8 import org.apache.shiro.subject.PrincipalCollection;
 9 import org.springframework.beans.factory.annotation.Autowired;
10 
11 /**
12  * 自定義Realm
13  */
14 public class MyRealm extends AuthorizingRealm {
15     @Autowired
16     private UserDao userDao;
17 
18     // 受權處理
19     @Override
20     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
21         return null;
22     }
23 
24     // 認證處理
25     @Override
26     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
27         // 編寫Shiro判斷邏輯,判斷帳號和密碼
28         // 一、判斷帳號
29         UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
30 
31         User user = userDao.findByUsername(token.getUsername());
32         if (user == null) {
33             // 帳號錯誤,Shiro底層會拋出UnknownAccountException異常
34             return null;
35         }
36 
37         // 二、判斷密碼
38         return new SimpleAuthenticationInfo("", user.getPassword(), "");
39     }
40 }

 

六、編寫實體類User.java

 1 package cn.temptation.domain;
 2 
 3 import javax.persistence.*;
 4 
 5 @Entity
 6 @Table(name = "sys_user")
 7 public class User {
 8     @Id
 9     @GeneratedValue(strategy = GenerationType.IDENTITY)
10     @Column(name = "userid")
11     private Integer userid;
12 
13     @Column(name = "username")
14     private String username;
15 
16     @Column(name = "password")
17     private String password;
18 
19     public Integer getUserid() {
20         return userid;
21     }
22 
23     public void setUserid(Integer userid) {
24         this.userid = userid;
25     }
26 
27     public String getUsername() {
28         return username;
29     }
30 
31     public void setUsername(String username) {
32         this.username = username;
33     }
34 
35     public String getPassword() {
36         return password;
37     }
38 
39     public void setPassword(String password) {
40         this.password = password;
41     }
42 }

 

七、編寫控制器類UserController.java

 1 package cn.temptation.web;
 2 
 3 import org.apache.shiro.SecurityUtils;
 4 import org.apache.shiro.authc.IncorrectCredentialsException;
 5 import org.apache.shiro.authc.UnknownAccountException;
 6 import org.apache.shiro.authc.UsernamePasswordToken;
 7 import org.apache.shiro.subject.Subject;
 8 import org.springframework.stereotype.Controller;
 9 import org.springframework.ui.Model;
10 import org.springframework.web.bind.annotation.RequestMapping;
11 
12 @Controller
13 public class UserController {
14     // 訪問登陸頁
15     @RequestMapping("/login")
16     public String login() {
17         return "login";
18     }
19 
20     // 訪問首頁
21     @RequestMapping("/index")
22     public String index() {
23         return "index";
24     }
25 
26     // 登陸處理
27     @RequestMapping("/doLogin")
28     public String doLogin(String username, String password, Model model) {
29         // 使用Shiro編寫認證處理
30         // 一、獲取Subject
31         Subject subject = SecurityUtils.getSubject();
32 
33         // 二、封裝用戶數據
34         UsernamePasswordToken token = new UsernamePasswordToken(username, password);
35 
36         // 三、執行登陸
37         try {
38             // 登陸成功
39             subject.login(token);
40 
41             // 返回當前用戶的賬號
42             model.addAttribute("currentuser", token.getUsername());
43 
44             return "index";
45         } catch (UnknownAccountException exception) {
46             // 返回錯誤信息
47             model.addAttribute("msg", "帳號錯誤!");
48 
49             return "login";
50         } catch (IncorrectCredentialsException exception) {
51             // 返回錯誤信息
52             model.addAttribute("msg", "密碼錯誤!");
53 
54             return "login";
55         }
56     }
57 
58     // 註銷處理
59     @RequestMapping("/doLogout")
60     public String doLogout() {
61         // 一、獲取Subject
62         Subject subject = SecurityUtils.getSubject();
63 
64         // 二、執行註銷
65         try {
66             subject.logout();
67         } catch (Exception ex) {
68             ex.printStackTrace();
69         } finally {
70             return "login";
71         }
72     }
73 }

 

八、編寫數據訪問接口UserDao.java

 1 package cn.temptation.dao;
 2 
 3 import cn.temptation.domain.User;
 4 import org.springframework.data.jpa.repository.JpaRepository;
 5 import org.springframework.data.jpa.repository.Query;
 6 import org.springframework.data.repository.query.Param;
 7 
 8 public interface UserDao extends JpaRepository<User, Integer> {
 9     // 根據帳號查詢用戶
10     @Query(value = "SELECT * FROM sys_user WHERE username=:username", nativeQuery = true)
11     User findByUsername(@Param("username") String username);
12 }

 

九、項目結構

 

十、運行效果

相關文章
相關標籤/搜索