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文件如下:

    <?xml version="1.0" encoding="UTF-8"?>


    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

    <properties>
    	<java.version>1.8</java.version>
    </properties>
    
    <dependencies>
    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-thymeleaf</artifactId>
    	</dependency>
    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-web</artifactId>
    	</dependency>
    	<dependency>
    		<groupId>mysql</groupId>
    		<artifactId>mysql-connector-java</artifactId>
    		<scope>runtime</scope>
    	</dependency>
    	<dependency>
    		<groupId>org.projectlombok</groupId>
    		<artifactId>lombok</artifactId>
    		<optional>true</optional>
    	</dependency>
    	<dependency>
    		<groupId>org.apache.shiro</groupId>
    		<artifactId>shiro-spring</artifactId>
    		<version>1.5.3</version>
    	</dependency>
    	<dependency>
    		<groupId>com.baomidou</groupId>
    		<artifactId>mybatis-plus-boot-starter</artifactId>
    		<version>3.3.1.tmp</version>
    	</dependency>
    	<dependency>
    		<groupId>com.github.theborakompanioni</groupId>
    		<artifactId>thymeleaf-extras-shiro</artifactId>
    		<version>2.0.0</version>
    	</dependency>
    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-test</artifactId>
    		<scope>test</scope>
    		<exclusions>
    			<exclusion>
    				<groupId>org.junit.vintage</groupId>
    				<artifactId>junit-vintage-engine</artifactId>
    			</exclusion>
    		</exclusions>
    	</dependency>
    </dependencies>
    <build>
    	<plugins>
    		<plugin>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-maven-plugin</artifactId>
    		</plugin>
    	</plugins>
    </build>
    
  • 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);
    

    }

  • 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<Account> wrapper = new QueryWrapper<Account>();
    	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);
    }
    

    }

  • 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<String> 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;
    }
    

    }

  • 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<String,String> map = new HashMap<String, String>();
    //登录状态下才可以访问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();
    }
    

    }

  • 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";
    	}
    }
    

    }

  • 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);
    	
    }
    

    }

  • index页面

    Insert title here
    <a href="/main">main</a> 
    <span shiro:hasPermission="manage"> | <a href="/manage">manage</a></span>
    <span shiro:hasRole="admin"> | <a href="/admin">admin</a></span>
    
    <br>
    <h1>index</h1>
    
  • 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值