zoukankan      html  css  js  c++  java
  • 【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限

    开发环境搭建参见《【原】无脑操作:IDEA + maven + SpringBoot + JPA + Thymeleaf实现CRUD及分页

    需求:

    ① 除了登录页面,在地址栏直接访问其他URL,均跳转至登录页面

    ② 登录涉及帐号和密码,帐号错误提示帐号错误,密码错误提示密码错误

    ③ 登录成功跳转至首页,首页显示登录者帐号信息,并有注销帐号功能,点击注销退出系统

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

    分析:

    典型的运用认证权限的需求,考虑使用Shiro。了解一下Shiro框架,Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。


    关键词汇:

    ① 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;

    1、编写项目对象模型文件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>

    2、编写项目配置文件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

    3、编写项目启动类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 }

    4、编写登录页面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>

    5、编写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     // 1、创建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     // 2、创建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     // 3、创建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         // 1、判断账号
    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         // 2、判断密码
    38         return new SimpleAuthenticationInfo("", user.getPassword(), "");
    39     }
    40 }

    6、编写实体类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 }

    7、编写控制器类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         // 1、获取Subject
    31         Subject subject = SecurityUtils.getSubject();
    32 
    33         // 2、封装用户数据
    34         UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    35 
    36         // 3、执行登录
    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         // 1、获取Subject
    62         Subject subject = SecurityUtils.getSubject();
    63 
    64         // 2、执行注销
    65         try {
    66             subject.logout();
    67         } catch (Exception ex) {
    68             ex.printStackTrace();
    69         } finally {
    70             return "login";
    71         }
    72     }
    73 }

    8、编写数据访问接口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 }

    9、项目结构

    10、运行效果

  • 相关阅读:
    MySQL Partition--分区基础
    MySQL Replication--跳过复制错误
    MySQL--SHOW PROCESSLIST
    MySQL InnoDB Engine--缓冲器数据交换
    MySQL InnoDB Engine--数据预热
    MySQL Profiling--常用命令
    Linux--用户管理
    vi和vim快捷键的使用
    vi和vim
    xftp使用
  • 原文地址:https://www.cnblogs.com/iflytek/p/9842269.html
Copyright © 2011-2022 走看看