zoukankan      html  css  js  c++  java
  • 学习springboot+shiro的实际应用demo

    学习springboot+shiro的应用

    一、创建一个springbootweb项目

     

     

     

     

     

    至此项目建成,完整项目目录如下:

     

    运行项目:

     

    运行结果如下:

     

    二、配置shiro

    首先是导入jar包:


    <!--shiro模板-->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.4.1</version>
    </dependency>


    <!--thymeleaf模板-->
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
    </dependency>

    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-java8time</artifactId>
    </dependency>

    其中thymeleaf只要是前台要用

    下面是index.html的代码:

    <!DOCTYPE html>
    <html lang="en" xmlns:th = "http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
    </head>
    <body>

    <h1>首页</h1>
    <p th:text="${msg}"></p>
    <hr>

    <a th:href="@{/user/add}">add</a> | <a th:href="@{/user/update}">update</a>

    </body>
    </html>

     

    接下来是MyController 的全部代码,即demo所需全部controller:

    package com.song.shirodemo.controller;

    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.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;

    @Controller
    public class MyController {

        @RequestMapping(value = {"/","/index"})
        public String toIndex(Model model){
            model.addAttribute("msg","hello,Shiro");
            return "index";
        }

        @RequestMapping("/user/add")
        public String add(){
            return "user/add";
        }

        @RequestMapping("/user/update")
        public String update(){
            return "user/update";
        }

        @RequestMapping("/toLogin")
        public String toLogin(){
            return "login";
        }

        @RequestMapping("/login")
        public String login(String username,String password,Model model){
            //获取当前的用户
            Subject subject = SecurityUtils.getSubject();
            //封装用户的登录数据
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);

            try {
                subject.login(token);//执行登录方法,如果没有异常就说明ok了
                return "index";
            } catch (UnknownAccountException e) {//用户名不存在
                model.addAttribute("msg","用户名错误");
    //            e.printStackTrace();
                return "login";
            }catch (IncorrectCredentialsException e) {//密码错误或不存在
                model.addAttribute("msg","密码错误");
                return "login";
            }


        }

        @ResponseBody
        @RequestMapping("/noauth")
        public String unauthorized(){
            return "未经授权无法访问此页面";
        }

        @RequestMapping("/logout")
        public String logout(String username,String password,Model model){
            //获取当前的用户
            Subject currentUser = SecurityUtils.getSubject();
            currentUser.logout();
            return "login";
        }

    }

    接下来是三个要用到的页面目录结构:

    下面是login.html的代码:

    <!DOCTYPE html>
    <html lang="en" xmlns:th = "http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>登录</h1>
    <hr>

    <p th:text="${msg}" style="color: red;"></p>
    <form th:action="@{/login}">
        <p>用户名:<input type="text" name="username"></p>
        <p>密码:<input type="text" name="password"></p>
        <p><input type="submit"></p>
    </form>

    </body>
    </html>

    add.html的代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>add</title>
    </head>
    <body>

    <h1>add</h1>

    </body>
    </html>

    update.html的代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>update</title>
    </head>
    <body>
    <h1>update</h1>
    </body>
    </html>

    此时把 @RequestMapping("/login"里的内容注释掉只留一个:

    return "index";

    可以正常运行跳转。

    三、添加shiro

    结构目录如下:

    1.添加UserRealm

     

    代码如下:

    package com.example.demo.config;

    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;

    public class UserRealm extends AuthorizingRealm {
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            return null;
        }

        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            return null;
        }
    }

    2.添加ShiroConfig设置,注意不要少了注解

    代码如下:

    package com.example.demo.config;

    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;

    @Configuration
    public class ShiroConfig {

        //ShiroFilterFactoryBean
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(securityManager);

            //添加shiro的内置过滤器
            /*
                anon: 无需认证就可以访问
                authc: 必须认证了才能访问
                user: 必须拥有 记住我 功能才能用
                perms: 拥有对某个资源的权限才能访问
                role: 拥有某个角色权限才能访问
             */

            //登录拦截
            Map<String,String> filterMap = new LinkedHashMap<>();
            filterMap.put("/user/add","authc");
            filterMap.put("/user/update","authc");

            bean.setFilterChainDefinitionMap(filterMap);

            //设置登录的请求
            bean.setLoginUrl("/toLogin");

            return bean;
        }

        //DefaultWebSecurityManager
        @Bean(name="securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //关联 UserRealm
            securityManager.setRealm(userRealm);
            return securityManager;
        }

        //创建 realm 对象 , 需要自定义类1 ,@Bean被Spring托管了
        @Bean
        public UserRealm userRealm(){
            return new UserRealm();
        }
    }

     

    至此shiro基本配置已经完成,运行项目时会自动拦截:

     

    四、加上mybatis以及shiro和thymeleaf整合

    1.添加jar包

    <!--shiro-thymeleaf整合-->
    <dependency>
        <groupId>com.github.theborakompanioni</groupId>
        <artifactId>thymeleaf-extras-shiro</artifactId>
        <version>2.0.0</version>
    </dependency>


    <!--mybatis配置 start-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.0</version>
    </dependency>

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.12</version>
    </dependency>
    <!--mybatis配置 end-->

    2.添加mybatis的配置文件

    机构目录如下:

     

    (1)application.yml

    spring:
      datasource:
        #   数据源基本配置
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/sxh?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
        type: com.alibaba.druid.pool.DruidDataSource
        #   数据源其他配置
        initialSize: 5
        minIdle: 5
        maxActive: 20
        maxWait: 60000
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
        validationQuery: SELECT 1 FROM DUAL
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        poolPreparedStatements: true
        #   配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
        filters: stat,wall,log4j
        maxPoolPreparedStatementPerConnectionSize: 20
        useGlobalDataSourceStat: true
        connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

     

     

    (2)application.properties

      mybatis.type-aliases-package=com.example.demo.pojo
      mybatis.mapper-locations=classpath:mapper/*.xml

     

    3.添加UserService所需要的相关文件

    1)实体类

    package com.example.demo.pojo;


    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {

        private int id;
        private String name;
        private String pwd;
        private String perms;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getPwd() {
            return pwd;
        }

        public void setPwd(String pwd) {
            this.pwd = pwd;
        }

        public String getPerms() {
            return perms;
        }

        public void setPerms(String perms) {
            this.perms = perms;
        }
    }

     

    2)UserMapper类:

    package com.example.demo.mapper;

    import com.example.demo.pojo.User;
    import org.apache.ibatis.annotations.Mapper;
    import org.springframework.stereotype.Repository;

    @Repository
    @Mapper
    public interface UserMapper {

        public User queryUserByName(String name);
    }

     

    3)mapper/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.example.demo.mapper.UserMapper">

        <!-- 通过name查询一个用户 -->
        <select id="queryUserByName" parameterType="String" resultType="User">
          select * from sxh.user where name=#{name};
       </select>


    </mapper>

     

    4)UserService接口

    package com.example.demo.service.userService;

    import com.example.demo.pojo.User;
    public interface UserService {
        public User queryUserByName(String name);
    }

    5)UserService接口的实现类UserServiceImpl

    package com.example.demo.service.userService.impl;

    import com.example.demo.mapper.UserMapper;
    import com.example.demo.pojo.User;
    import com.example.demo.service.userService.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    @Service
    public class UserServiceImpl implements UserService {

        @Autowired
        UserMapper userMapper;

        @Override
        public User queryUserByName(String name) {
            return userMapper.queryUserByName(name);
        }
    }

     

    4.修改shiro先关配置

    1)ShiroConfig中的getShiroFilterFactoryBean方法添加内容:

        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(securityManager);

            //添加shiro的内置过滤器
            /*
                anon: 无需认证就可以访问
                authc: 必须认证了才能访问
                user: 必须拥有 记住我 功能才能用
                perms: 拥有对某个资源的权限才能访问
                role: 拥有某个角色权限才能访问
             */

            //登录拦截
            Map<String,String> filterMap = new LinkedHashMap<>();
    //        filterMap.put("/user/add","authc");
    //        filterMap.put("/user/update","authc");

            //授权, 正常情况下,没授权会跳到未授权页面
            // 授权要放在前面?放后面就不管用了
            filterMap.put("/user/add","perms[user:add]");
            filterMap.put("/user/update","perms[user:update]");

            filterMap.put("/user/*","authc");

            //设置登录的请求
            bean.setLoginUrl("/toLogin");
            //未授权页面
            bean.setUnauthorizedUrl("/noauth");

            bean.setFilterChainDefinitionMap(filterMap);


            return bean;
        }

     

      2)给UserRealm添加内容,代码如下:

    package com.example.demo.config;

    import com.example.demo.pojo.User;
    import com.example.demo.service.userService.UserService;
    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.springframework.beans.factory.annotation.Autowired;

    public class UserRealm extends AuthorizingRealm {

        @Autowired
        UserService userService;


        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("执行了=>授权 doGetAuthorizationInfo");
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //        info.addStringPermission("user:add");
            //拿到当前登录的这个对象
            Subject subject = SecurityUtils.getSubject();
            User currentUser = (User) subject.getPrincipal();
            if(currentUser.getPerms()!=null){
                info.addStringPermission(currentUser.getPerms());
            }
            return info;
        }

        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            System.out.println("执行了=>认证 doGetAuthenticationInfo");
            UsernamePasswordToken userToken = (UsernamePasswordToken) token;
            //连接真实的数据库
            User user = userService.queryUserByName(userToken.getUsername());
            if(user==null){//没有这个人
                return null; //抛出异常 UnknownAccountException
            }
            //密码认证,shiro
            return new SimpleAuthenticationInfo(user,user.getPwd(),"");
        }
    }

     

    此时可以把MyController中的@RequestMapping("/login")中的注释都拿掉了

     

    对了忘记数据库了:

     

    接下来就是检验成果的时候了:

    登录

     

    ②index页面

     

    点击add未经授权无法访问此页面

     

    点击update跳转update页面

     

    至此,实际上已经结束了,关于shiro和thymeleaf的整合,主要是index.html页面,

    代码修改如下:

    <!DOCTYPE html>
    <html lang="en" xmlns:th = "http://www.thymeleaf.org"
          xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
    </head>
    <body>
    <h1>首页</h1>
    <p th:text="${msg}"></p>
    <hr>
    <div shiro:hasPermission="user:add">
        <a th:href="@{/user/add}">add</a>
    </div>
    <div shiro:hasPermission="user:update">
        <a th:href="@{/user/update}">update</a>
    </div>
    <a th:href="@{/logout}">logout</a>
    </body>
    </html>

    此时,没有user:add权限的就不再显示add的连接了,同样,没有user:update权限的也不再显示update的连接了。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    Android开发之 Android 的基本组件的概述
    Android开发之 Android应用程序详细解析
    Android开发之 Android应用程序目录结构解析
    第七篇 :微信公众平台开发实战Java版之如何获取微信用户基本信息
    Android 开发之Windows环境下Android Studio安装和使用教程(图文详细步骤)
    Android开发之 Windows环境下通过Eclipse创建的第一个安卓应用程序(图文详细步骤)
    Android 开发之 Android 开发的起步
    Github学习进阶-初露锋芒,通过命令行将本地git仓库推送到Github上面的仓库
    Windows环境下maven 安装与环境变量配置
    Github学习之路-小试牛刀,练习Git 的基本操作
  • 原文地址:https://www.cnblogs.com/fzly-88/p/12360417.html
Copyright © 2011-2022 走看看