欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Springboot集成shiro

程序员文章站 2022-05-26 08:50:42
...

Springboot集成shiro

项目目录

Springboot集成shiro

1,shiro简介:

subject:用户主体

security:安全管理器

Realm:shiro连接数据的桥梁

2,springboot集shiro

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.4.0</version>
</dependency>

3,自定义realm类

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) {
        System.out.println("执行授权逻辑");
        return null;
    }

    /*
    * 执行认证逻辑
    * */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行认证逻辑");
       
        String name = "wangxin";
        String password = "123456";

        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        //1.判断用户名
        if(!token.getUsername().equals(name)){
            return null;//shiro低层会抛出UnknownAccountException异常
        }
        //2.判断密码
        return new SimpleAuthenticationInfo("",password,"");
    }
}

4,编写shiro配置类

import org.apache.shiro.mgt.DefaultSecurityManager;
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;

@Configuration
public class shiroConfig {
    /*
    * 创建ShiroFilterFactoryBean
    *
    */
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        factoryBean.setSecurityManager(securityManager);
         /*
        * shiro内置过滤器,
        * 常用过滤器
        * anon:无需认证(登录),可以访问
        * authc:必须认证才可以访问
        * user:如果使用rememeber me就可以直接访问
        * perms:有资源权限才可以访问
        * role:必须得到角色权限才可以访问
        * */
        Map<String,String> filter = new LinkedHashMap<>();
        filter.put("/user/add","authc");
        filter.put("/user/update","authc");
        //默认跳转login.jsp
        //修改跳转的页面
        shiroFilterFactoryBean.setLoginUrl("/user/tologin");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filter);
        return factoryBean;
    }
    /*
    * 创建DefaultWebSecurityManager
    * */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    /*
    *
    * 创建realm
    * */
    @Bean(name ="userRealm")
    public UserRealm getrealm(){
        return new UserRealm();
    }
}

5,整合Mybatis实现登录认证

(1)导入依赖

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

<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.19</version>
</dependency>

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

(2)配置application.yml

datasource:
  driver-class-name: com.mysql.jdbc.Driver
  username: root
  password: root
  url: jdbc:mysql://localhost:3306/db_cqb?serverTimezone=UTC
  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
  maxPoolPreparedStatementPerConnectionSize: 20
  filters: stat,wall
  connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

mybatis:
  type-aliases-package: com.godx.entity

(3) 编写user实体类

public class User {
    private Integer id;
    private String username;
    private String password;
    private String role;
    public User(){}

    public User(Integer id, String username, String password, String role) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.role = role;
    }

    public Integer getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}

(4) 编写UserMapper接口

public interface UserMapper {
    public User findByName(String username);
    public User findById(Integer id);
}

(5)编写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.godx.mapper.UserMapper">
    <select id="findByName" resultType="user">
            select * from user where username = #{username};
    </select>
    <select id="findById" resultType="user">
            select * from user where id = #{id};
    </select>
</mapper>


(6)编写UserService接口和UserServiceImpl实现类

import com.godx.entity.User;

public interface UserService {
    public User findByName(String username);
    public User findById(Integer id);
}


import com.godx.entity.User;
import com.godx.mapper.UserMapper;
import com.godx.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public User findByName(String username) {
       User user = userMapper.findByName(username);
       return user;
    }
}

(7)编写UserController类

import com.godx.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.sql.SQLOutput;

@Controller
@RequestMapping("/user")
@Api(tags = "user")
public class UserController {
    @Autowired
    private UserService userService;

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

    @RequestMapping("/add")
    public String add(){
        return "addUser";
    }
    @RequestMapping("/tologin")
    public String tologin(){
        return "login";
    }
    @RequestMapping("/update")
    public String upate(){
        return "updateUser";
    }

    @RequestMapping("/login")
    public String login(String username, String password, Model model){
        /*
        * 使用shiro编写用户登录*/
        //1.获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        //2,封装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        //3,执行登录
        try {
            subject.login(token);
            return "test";
        }catch (UnknownAccountException e){
            model.addAttribute("msg","用户名不存在");
            return "login";
        }catch (IncorrectCredentialsException e){
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }
    /*@ApiOperation(value = "好人",notes = "hr")
    @RequestMapping("/good")
    public String good(){
        return "You are a good man!";
    }*/

}

6,修改UserRealm

 @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行认证逻辑");
       /* String name = "wangxin";
        String password = "123456";*/
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        User user = userService.findByName(token.getUsername());
        System.out.println(user.getUsername()+"/"+user.getPassword());
        //1.判断用户名
        if(user==null){
            return null;//shiro低层会抛出UnknownAccountException异常
        }
        //2.判断密码
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }

7,Html页面

(1)login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3 style="color: red" th:text="${msg}"></h3>
    <form method="post" action="/user/login">
        <div>
            用户名:<input type="text" name="username">
        </div>
        <div>
            密码:<input type="password" name="password">
        </div>
        <div>
            <input type="submit" value="登录">
        </div>
    </form>
</body>
</html>

其他页面简单不放出来了

8,SpringBoot整合Shiro实现用户授权

(1) 使用shiro内置过滤器进行拦截

将原来的ShiroConfig修改成以下

 @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean  shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        /*
        * shiro内置过滤器,
        * 常用过滤器
        * anon:无需认证(登录),可以访问
        * authc:必须认证才可以访问
        * user:如果使用rememeber me就可以直接访问
        * perms:有资源权限才可以访问
        * role:必须得到角色权限才可以访问
        * */
        Map<String,String> filter = new LinkedHashMap<>();
        filter.put("/user/add","authc");
        filter.put("/user/update","authc");
        filter.put("/user/hello","authc");

        //授权过滤器
        //注意:当前授权拦截后,shiro会自动跳转到未授权的页面
        //filter.put("/user/add","perms[user:add]");
        
       	//连接数据库动态查询
        filter.put("/user/add","perms[admin]");
        filter.put("/user/update","perms[test]");
        //设置权限不够跳转的页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/user/noAuth");
        //默认跳转login.jsp
        //修改跳转的页面
        shiroFilterFactoryBean.setLoginUrl("/user/tologin");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filter);
        return shiroFilterFactoryBean;
    }

(2)关联数据库动态授权

修改UserRealm

	@Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行授权逻辑");
        //给资源进行授权:
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //获取当前的用户
        Subject subject = SecurityUtils.getSubject();
        User user  = (User) subject.getPrincipal();
        User dbuser = userService.findById(user.getId());
        simpleAuthorizationInfo.addStringPermission(dbuser.getRole());
        return simpleAuthorizationInfo;
    }

9,thymeleaf整合shiro标签

(1)导入依赖

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
</dependency>

(2)配置ShiroDialect

在ShiroConfig配置类中加入以下代码

 /*
    *
    * 配置ShiroDialect用于thymeleaf和shiro的标签*/
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }

(3)test.html页面修改

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div shiro:hasPermission="admin">
<a href="/user/add">用户添加</a>
</div>
<div shiro:hasPermission="test">
<a href="/user/update">用户修改</a>
</div>
</body>
</html>

10,安全退出

(1)UserController添加logout方法

@RequestMapping("/logout")
public String logout(){
    Subject subject = SecurityUtils.getSubject();
    subject.logout();
    return "login";
}

项目源码