zoukankan      html  css  js  c++  java
  • springboot+shiro

    1.springboot整合shiro

    pom.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
     4     <modelVersion>4.0.0</modelVersion>
     5     <parent>
     6         <groupId>org.springframework.boot</groupId>
     7         <artifactId>spring-boot-starter-parent</artifactId>
     8         <version>2.2.1.RELEASE</version>
     9         <relativePath/> <!-- lookup parent from repository -->
    10     </parent>
    11     <groupId>com.qiao</groupId>
    12     <artifactId>hello-shiro</artifactId>
    13     <version>0.0.1-SNAPSHOT</version>
    14     <name>hello-shiro</name>
    15     <description>Demo project for Spring Boot</description>
    16 
    17     <properties>
    18         <java.version>1.8</java.version>
    19     </properties>
    20 
    21     <dependencies>
    22         <dependency>
    23             <groupId>org.springframework.boot</groupId>
    24             <artifactId>spring-boot-starter-web</artifactId>
    25         </dependency>
    26 
    27         <dependency>
    28             <groupId>org.springframework.boot</groupId>
    29             <artifactId>spring-boot-starter-test</artifactId>
    30             <scope>test</scope>
    31             <exclusions>
    32                 <exclusion>
    33                     <groupId>org.junit.vintage</groupId>
    34                     <artifactId>junit-vintage-engine</artifactId>
    35                 </exclusion>
    36             </exclusions>
    37         </dependency>
    38         <!-- shiro thymeleaf整合 -->
    39         <dependency>
    40             <groupId>com.github.theborakompanioni</groupId>
    41             <artifactId>thymeleaf-extras-shiro</artifactId>
    42             <version>2.0.0</version>
    43         </dependency>
    44         <dependency>
    45             <groupId>org.projectlombok</groupId>
    46             <artifactId>lombok</artifactId>
    47         </dependency>
    48         <!-- 引入mysql驱动包 -->
    49         <dependency>
    50             <groupId>mysql</groupId>
    51             <artifactId>mysql-connector-java</artifactId>
    52             <version>5.1.27</version>
    53         </dependency>
    54         <!-- 引入Druid依赖,阿里巴巴所提供的数据源 -->
    55         <dependency>
    56             <groupId>com.alibaba</groupId>
    57             <artifactId>druid</artifactId>
    58             <version>1.0.29</version>
    59         </dependency>
    60         <dependency>
    61             <groupId>org.mybatis.spring.boot</groupId>
    62             <artifactId>mybatis-spring-boot-starter</artifactId>
    63             <version>2.1.0</version>
    64         </dependency>
    65         <dependency>
    66             <groupId>org.springframework.boot</groupId>
    67             <artifactId>spring-boot-starter-thymeleaf</artifactId>
    68         </dependency>
    69         <dependency>
    70             <groupId>org.apache.shiro</groupId>
    71             <artifactId>shiro-spring</artifactId>
    72             <version>1.4.1</version>
    73         </dependency>
    74     </dependencies>
    75 
    76     <build>
    77         <plugins>
    78             <plugin>
    79                 <groupId>org.springframework.boot</groupId>
    80                 <artifactId>spring-boot-maven-plugin</artifactId>
    81             </plugin>
    82 
    83         </plugins>
    84 
    85     </build>
    86 
    87 </project>
    View Code

    其中shiro整合spring的依赖是

    1 <dependency>
    2     <groupId>org.apache.shiro</groupId>
    3     <artifactId>shiro-spring</artifactId>
    4     <version>1.4.1</version>
    5 </dependency>

    shiro和thymeleaf整合的依赖是

    1  <dependency>
    2      <groupId>com.github.theborakompanioni</groupId>
    3      <artifactId>thymeleaf-extras-shiro</artifactId>
    4      <version>2.0.0</version>
    5   </dependency>

    2.shiro核心的API

      1.Subject:主体,当前用户,与当前应用进行交互。所有Subject都要绑定到SercurityManager。

      2.SecurityManager:安全管理器 ,管理所有的Subject,所有关于安全的操作都会与之交互。

      3.Realm:域,Shiro从Realm获取授权,认证,安全管理器认证用户身份就需要从Realm获取用户进行比较。

      使用Shiro需要自定义Realm继承AuthorizingRealm

      覆写两个方法即可

      

       AuthenticationInfo 用于认证

      AuthorizationInfo 用于授权

    3.使用shiro

    配置ShiroConfig

     1 @Configuration
     2 public class ShiroConfig {
     3     //ShiroFilterFactoryBean 3.
     4     @Bean
     5     public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
     6         ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
     7         //设置安全管理器
     8         bean.setSecurityManager(securityManager);
     9         //添加shiro的内置管理器
    10         /**
    11          * anon:无需认证即可访问
    12          * authc:必须认证才能访问
    13          * user:必须拥有 记住我 功能
    14          * perms:拥有对某个资源的权限才能访问
    15          * role:拥有某个角色权限才能访问
    16          * filter.put("/user/add", "authc");
    17          * filter.put("/user/update", "authc");
    18          */
    19         //拦截
    20         Map<String, String> filter = new LinkedHashMap<>();
    21         //授权 必须是user:add权限的才能访问
    22         filter.put("/user/add", "perms[user:add]");
    23         //授权 必须是user:add权限的才能访问
    24         filter.put("/user/update", "perms[user:update]");
    25         filter.put("/user/*", "authc");
    26         bean.setFilterChainDefinitionMap(filter);
    27         //设置登录的请求
    28         bean.setLoginUrl("/toLogin");
    29         //设置未授权请求页面
    30         bean.setUnauthorizedUrl("/unAuthor");
    31         return bean;
    32     }
    33 
    34     //DefaultWebSecurityManager 2.
    35     @Bean(name = "securityManager")
    36     public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm){
    37         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    38         //关联UserRealm
    39         securityManager.setRealm(userRealm);
    40         return securityManager;
    41     }
    42 
    43     //创建realm类,自定义
    44     @Bean
    45     public UserRealm userRealm(){
    46         return new UserRealm();
    47     }
    48 
    49     //整合shiroDialect 用于thymeleaf和shiro标签配合使用
    50     @Bean
    51     public ShiroDialect shiroDialect(){
    52         return new ShiroDialect();
    53     }
    54 }

    自定义UserRealm

     1 public class UserRealm extends AuthorizingRealm {
     2     @Autowired
     3     UserService userService;
     4     //授权
     5     @Override
     6     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
     7         System.out.println("执行授权==》doGetAuthorizationInfo");
     8 
     9         SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    10 
    11         //拿到当前登录的这个对象
    12         Subject subject = SecurityUtils.getSubject();
    13         User currentUser = (User) subject.getPrincipal();
    14         //如果没有权限,权限为null,就返回null
    15         if (currentUser.getPerms() == null){
    16             return null;
    17         }
    18         //设置权限~从数据库查寻
    19         info.addStringPermission(currentUser.getPerms());
    20         return info;
    21     }
    22     //认证
    23     @Override
    24     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
    25             throws AuthenticationException {
    26         System.out.println("执行认证==》AuthenticationInfo");
    27        //连接真实的数据库
    28         UsernamePasswordToken userToken = (UsernamePasswordToken) token;
    29         User user = userService.queryUserByName(userToken.getUsername());
    30         //把登录用户塞进shiro的session shiro有自己独立的session~这也是为什么shiro可以脱离web使用
    31         Subject subject = SecurityUtils.getSubject();
    32         Session session = subject.getSession();
    33         session.setAttribute("loginUser", user);
    34         if(user == null){
    35             throw new UnknownAccountException();
    36         }
    37         //盐值
    38         String saltPassword = ShiroUtil.saltPassword(userToken.getPassword(), user.getSaltValue());
    39         // userToken.getPassword() 获取用户输入的密码
    40         if (!user.getPwd().equals(saltPassword)){
    41             throw new IncorrectCredentialsException();
    42         }
    43         //密码认证,由shiro做~ 为了防止密码泄露  第4个参数是realm名称
    44         return new SimpleAuthenticationInfo(user, userToken.getPassword(), ByteSource.Util.bytes(user.getSaltValue()), this.getName());
    45     }
    46 }

    需要密码加密,创建工具类ShiroUtil

     1 public class ShiroUtil {
     2     public static String createSalt(){
     3         //生成32的随机盐值
     4         return UUID.randomUUID().toString().replaceAll("-", "");
     5     }
     6     /**
     7      * @param srcPwd    原始密码
     8      * @param saltValue 盐值
     9      */
    10     public static String saltPassword(Object srcPwd, String saltValue){
    11         return new SimpleHash("MD5", srcPwd, saltValue, 1024).toString();
    12     }
    13 }

    创建实体类User

     1 @Data
     2 @AllArgsConstructor
     3 @NoArgsConstructor
     4 public class User {
     5     private Integer id;
     6     private String name;
     7     private String pwd;
     8     private String perms;
     9     /**
    10      * 盐值
    11      */
    12     private String saltValue;
    13 
    14 }

    我这里使用的mybatis,创建UserMapper接口,直接使用注解写sql(不喜欢XML)

    1 @Repository
    2 @Mapper
    3 public interface UserMapper {
    4     @Select("select * from mybatis.user where name = #{name}")
    5     public User queryUserByName(String name);
    6     @Insert("insert into mybatis.user(name,pwd,perms,saltValue) values(#{name},#{pwd},#{perms},#{saltValue})")
    7     public void insertUser(User user);
    8 }

    创建Service接口和实现类,用于获取数据

    1 public interface UserService {
    2     public User queryUserByName(String name);
    3     public void insertUser(User user);
    4 }
     1 @Service
     2 public class UserServiceImpl implements UserService {
     3     @Autowired
     4     UserMapper userMapper;
     5     @Override
     6     public User queryUserByName(String name) {
     7         return userMapper.queryUserByName(name);
     8     }
     9 
    10     @Override
    11     public void insertUser(User user) {
    12         userMapper.insertUser(user);
    13     }
    14 }

    创建一个简陋的主页、登录和注册页面

    index.html

     1 <!DOCTYPE html>
     2 <html lang="en" xmlns:th="http://www.thymeleaf.org"
     3       xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
     4 <head>
     5     <meta charset="UTF-8">
     6     <title>首页</title>
     7 </head>
     8 <body>
     9     <h1>首页</h1>
    10     <div th:if="${session.loginUser==null}">
    11         <a th:href="@{/toLogin}">登录</a>
    12     </div>
    13     <div th:if="${session.loginUser==null}">
    14         <a th:href="@{/toRegister}">注册</a>
    15     </div>
    16     <div th:if="${session.loginUser!=null}">
    17         <a th:href="@{/logout}">退出</a>
    18     </div>
    19     <p>hello,shiro</p>
    20     <div shiro:hasPermission="user:add">
    21         <a th:href="@{/user/add}">add</a>
    22     </div>
    23     <div shiro:hasPermission="user:update">
    24     <a th:href="@{/user/update}">update</a>
    25     </div>
    26 </body>
    27 </html>

       xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro" 在thymeleaf中使用shiro标签的命名空间

    login.html

     1 <!DOCTYPE html>
     2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>登录</title>
     6 </head>
     7 <body>
     8 <p th:text="${msg}" style="color: red;"></p>
     9 <form th:action="@{/login}" method="post">
    10     <p>用户名:<input type="text" name="username"></p>
    11     <p>&emsp;码:<input type="text" name="password"></p>
    12     <input type="submit">
    13 </form>
    14 </body>
    15 </html>

    register.html

     1 <!DOCTYPE html>
     2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>注册</title>
     6 </head>
     7 <body>
     8 <h1>注册</h1>
     9 <form th:action="@{/register}" method="post">
    10     <p>用户名:<input type="text" name="username"></p>
    11     <p>&emsp;码:<input type="text" name="password"></p>
    12     <input type="submit">
    13 </form>
    14 </body>
    15 </html>

    yml配置文件

     1 spring:
     2   datasource:
     3     username: root
     4     password: 123456
     5     #?serverTimezone=UTC解决时区的报错
     6     url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
     7     driver-class-name: com.mysql.jdbc.Driver
     8     type: com.alibaba.druid.pool.DruidDataSource
     9 
    10     #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    11     #druid 数据源专有配置
    12     initialSize: 5
    13     minIdle: 5
    14     maxActive: 20
    15     maxWait: 60000
    16     timeBetweenEvictionRunsMillis: 60000
    17     minEvictableIdleTimeMillis: 300000
    18     validationQuery: SELECT 1 FROM DUAL
    19     testWhileIdle: true
    20     testOnBorrow: false
    21     testOnReturn: false
    22     poolPreparedStatements: true
    23 
    24     #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    25     #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    26     #则导入 log4j 依赖即可,Maven 地址: https://mvnrepository.com/artifact/log4j/log4j
    27     filters: stat,wall,log4j
    28     maxPoolPreparedStatementPerConnectionSize: 20
    29     useGlobalDataSourceStat: true
    30     connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

    数据表

    非原创,仅是在学习西部狂神-秦疆的课程的基础上加了撒盐加密的功能

    附上参考代码,继续努力~ https://github.com/Sevenwsq/springboot-shiro.git

  • 相关阅读:
    第一章--linux基础
    深入浅出OOP(一): 多态和继承(早期绑定/编译时多态)
    LeetCode Letter Combinations of a Phone Number
    ios 仿android gallery控件
    android何如获取SIM卡提供国家代码(ISO)
    android 获取 imei号码
    overridePendingTransition的简介
    转 Android Activity之间动画完整版详解
    【android开发】使用PopupWindow实现页面点击顶部弹出下拉菜单
    Android 带你从源码的角度解析Scroller的滚动实现原理
  • 原文地址:https://www.cnblogs.com/seekknowledge/p/11892049.html
Copyright © 2011-2022 走看看