• SpringBoot与Shiro整合(认证、授权和密码加密)


    SpringBoot与Shiro整合(认证、授权和密码加密)


    • 创建SpringBoot项目,选择以下工具包:

      Lombok
      Spring Web
      Thymeleaf
      MySQL Driver

    • 添加MybatisPlus的依赖:

      com.baomidou mybatis-plus-boot-starter 3.3.1.tmp
    • 添加Shiro的依赖:

      org.apache.shiro shiro-spring 1.5.3
    • 添加Shiro控制ThymeLeaf界面按钮级权限的依赖:

      com.github.theborakompanioni thymeleaf-extras-shiro 2.0.0
    • 完整的pom文件如下:


      4.0.0

      org.springframework.boot
      spring-boot-starter-parent
      2.3.1.RELEASE


      com.blu
      springboot-shiro
      0.0.1-SNAPSHOT
      springboot-shiro
      Demo project for Spring Boot

      
      	1.8
      
      
      
      	
      		org.springframework.boot
      		spring-boot-starter-thymeleaf
      	
      	
      		org.springframework.boot
      		spring-boot-starter-web
      	
      	
      		mysql
      		mysql-connector-java
      		runtime
      	
      	
      		org.projectlombok
      		lombok
      		true
      	
      	
      		org.apache.shiro
      		shiro-spring
      		1.5.3
      	
      	
      		com.baomidou
      		mybatis-plus-boot-starter
      		3.3.1.tmp
      	
      	
      		com.github.theborakompanioni
      		thymeleaf-extras-shiro
      		2.0.0
      	
      	
      		org.springframework.boot
      		spring-boot-starter-test
      		test
      		
      			
      				org.junit.vintage
      				junit-vintage-engine
      			
      		
      	
      
      
      	
      		
      			org.springframework.boot
      			spring-boot-maven-plugin
      		
      	
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
    • application.yml配置文件:

      spring:
      datasource:
      driver-class-name: com.mysql.cj.jdbc.Driver
      username: root
      password: 123456
      url: jdbc:mysql://localhost:3306/shirotest?useUnicode=true&characterEncoding=UTF-8

      thymeleaf:
      prefix: classpath:/templates/
      suffix: .html

      mybatis-plus:
      configuration:
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

    • Account实体类:

      package com.blu.entity;

      import com.baomidou.mybatisplus.annotation.IdType;
      import com.baomidou.mybatisplus.annotation.TableId;

      import lombok.Data;

      @Data
      public class Account {
      @TableId(value = “id”,type = IdType.AUTO)
      private Integer id;
      private String username;
      private String password;
      private String perms;
      private String role;
      private String salt;
      }

    • 实体类对应数据库:
      在这里插入图片描述

    • AccountMapper接口:

      package com.blu.mapper;

      import org.springframework.stereotype.Repository;
      import com.baomidou.mybatisplus.core.mapper.BaseMapper;
      import com.blu.entity.Account;

      @Repository
      public interface AccountMapper extends BaseMapper{

      }

    • AccountService接口:

      package com.blu.service;

      import com.blu.entity.Account;

      public interface AccountService {

      public Account findByUsername(String username);
      public void createAccount(Account account);
      
      • 1
      • 2

      }

    • AccountServiceImpl实现类:

      package com.blu.service.impl;

      import org.apache.shiro.crypto.SecureRandomNumberGenerator;
      import org.apache.shiro.crypto.hash.SimpleHash;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;

      import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
      import com.blu.entity.Account;
      import com.blu.mapper.AccountMapper;
      import com.blu.service.AccountService;

      @Service
      public class AccountServiceImpl implements AccountService{

      @Autowired
      private AccountMapper mapper;
      
      @Override
      public Account findByUsername(String name) {
      	QueryWrapper wrapper = new QueryWrapper();
      	wrapper.eq("username", name);
      	Account account = mapper.selectOne(wrapper);
      	return account;
      }
      
      @Override
      public void createAccount(Account account) {
      	//随机生成salt值,并通过用户注册的密码和salt值经两次md5算法生成真实存储的密码
      	String salt = new SecureRandomNumberGenerator().nextBytes().toString();
      	String password= new SimpleHash("md5",account.getPassword(),salt,2).toString();
      	account.setPassword(password);
      	account.setSalt(salt);
      	mapper.insert(account);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

      }

    • AccountRealm

      package com.blu.realm;

      import java.util.HashSet;
      import java.util.Set;

      import org.apache.shiro.SecurityUtils;
      import org.apache.shiro.authc.AuthenticationException;
      import org.apache.shiro.authc.AuthenticationInfo;
      import org.apache.shiro.authc.AuthenticationToken;
      import org.apache.shiro.authc.SimpleAuthenticationInfo;
      import org.apache.shiro.authc.UsernamePasswordToken;
      import org.apache.shiro.authz.AuthorizationInfo;
      import org.apache.shiro.authz.SimpleAuthorizationInfo;
      import org.apache.shiro.crypto.hash.SimpleHash;
      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;

      import com.blu.entity.Account;
      import com.blu.service.AccountService;

      public class AccountRealm extends AuthorizingRealm {

      @Autowired
      private AccountService accountService;
      
      /**
       * 授权
       */
      
      @Override
      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
      	//获取当前登录的用户信息
      	Subject subject = SecurityUtils.getSubject();
      	Account account = (Account) subject.getPrincipal();
      	//设置角色
      	Set rolesset = new HashSet<>();
      	rolesset.add(account.getRole());
      	SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(rolesset);
      	//设置权限
      	info.addStringPermission(account.getPerms());
      	return info;
      }
      
      /**
       * 认证
       */
      @Override
      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
      	UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
      	Account account = accountService.findByUsername(token.getUsername());
      	if(account != null){
      		//若密码不正确则返回IncorrectCredentialsException异常
      		return new SimpleAuthenticationInfo(account,account.getPassword(), getName());
      	}
      	//若用户名不存在则返回UnknownAccountException异常
      	return null;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35

      }

    • ShiroConfig配置类:

      package com.blu.config;

      import java.util.HashMap;
      import java.util.Map;

      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 com.blu.realm.AccountRealm;

      import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;

      @Configuration
      public class ShiroConfig {
      @Bean
      public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier(“securityManager”) DefaultWebSecurityManager securityManager){
      ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
      factoryBean.setSecurityManager(securityManager);
      Map map = new HashMap();
      //登录状态下才可以访问main页面,manage权限可访问manage页面,admin角色可访问admin页面
      map.put(“/main”, “authc”);
      map.put(“/manage”,“perms[manage]”);
      map.put(“/admin”, “roles[admin]”);
      factoryBean.setFilterChainDefinitionMap(map);
      //未登录状态下访问将跳转至login页面
      factoryBean.setLoginUrl(“/login”);
      //无授限状态下访问将请求unauthor
      factoryBean.setUnauthorizedUrl(“/unauthor”);
      return factoryBean;
      }

      @Bean
      public DefaultWebSecurityManager securityManager(@Qualifier("accoutRealm") AccountRealm accountRealm){
      	DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
      	manager.setRealm(accountRealm);
      	return manager;
      }
      
      @Bean
      public AccountRealm accoutRealm(){
      	return new AccountRealm();
      }
      @Bean
      public ShiroDialect shiroDialect(){
      	return new ShiroDialect();
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

      }

    • AccountController:

      package com.blu.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.crypto.hash.SimpleHash;
      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.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.PostMapping;
      import org.springframework.web.bind.annotation.ResponseBody;

      import com.blu.entity.Account;
      import com.blu.service.AccountService;

      @Controller
      public class AccountController {

      @Autowired
      private AccountService acccoutService;
      
      @GetMapping("/{url}")
      public String redirect(@PathVariable("url") String url) {
      	return url;
      }
      
      @PostMapping("/login")
      public String login(String username,String password,Model model) {
      	Subject subject = SecurityUtils.getSubject();
      	Account ac = acccoutService.findByUsername(username);
      	if(ac!=null) {
      		//根据salt值和用户输入的密码计算加密后的密码
      		String salt = ac.getSalt();
      		password = new SimpleHash("md5",password,salt,2).toString();
      	}
      	UsernamePasswordToken token = new UsernamePasswordToken(username,password);
      	try {
      		//将用户名和密码通过token传给shiro进行认证
      		subject.login(token);
      		Account account = (Account) subject.getPrincipal();
      		subject.getSession().setAttribute("account", account);
      		return "index";
      	} catch (UnknownAccountException e) {
      		e.printStackTrace();
      		model.addAttribute("msg", "用户名不存在");
      		return "login";
      	} catch (IncorrectCredentialsException e) {
      		e.printStackTrace();
      		model.addAttribute("msg", "密码有误");
      		return "login";
      	}
      	
      }
      
      @ResponseBody
      @GetMapping("/unauthor")
      public String unauthor() {
      	return "权限不足,无法访问";
      }
      
      @GetMapping("/logout")
      public String logout() {
      	Subject subject = SecurityUtils.getSubject();
      	subject.logout();
      	return "login";
      }
      
      @PostMapping("/register")
      public String register(Account account,Model model) {
      	String username = account.getUsername();
      	String password = account.getPassword();
      	if(username==null||username==""){
      		model.addAttribute("msg", "用户名不能为空");
      		return "register";
      	}else if(password==null||password=="") {
      		model.addAttribute("msg", "密码不能为空");
      		return "register";
      	}else if(acccoutService.findByUsername(username)!=null) {
      		model.addAttribute("msg", "用户名已被占用");
      		return "register";
      	}else {
      		acccoutService.createAccount(account);
      		return "login";
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67

      }

    • ShiroApplication启动类:

      package com.blu;

      import org.mybatis.spring.annotation.MapperScan;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;

      @SpringBootApplication
      @MapperScan(“com.blu.mapper”)
      public class ShiroApplication {

      public static void main(String[] args) {
      	SpringApplication.run(ShiroApplication.class, args);
      	
      }
      
      • 1
      • 2
      • 3
      • 4

      }

    • index页面

      Insert title here
      main 
       | manage
       | admin
      
      

      index

      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    • login页面

      Insert title here
      用户名:
      密码:
      注册
    • register页面

      Insert title here
      用户名:
      密码:
    • main/manage/admin页面

      Insert title here

      main

      Insert title here

      manage

      Insert title here

      admin

    项目源码:

    链接:https://pan.baidu.com/s/1EA-664JRpPOpfXaR6L_kkg 
    提取码:BLU0
    
    • 1
    • 2
  • 相关阅读:
    新消费时代,零售业的进与退?
    JavaSE错题收集
    比较聚合模型实战文本匹配
    玩转Mysql系列 - 第27篇:mysql如何确保数据不丢失?
    使用蒙特卡罗模拟期权定价
    在tdengine容器中生成初始化数据库的SH命令
    vue3 axios
    申请美国博士后的建议
    springboot基础入门
    南大通用GBase8s 常用SQL语句(238)
  • 原文地址:https://blog.csdn.net/m0_54850825/article/details/126596536