springboot整合shiro


使用 springboot整合shiro其实和使用 SSM整合shiro很相似,只不过使用springboot整合shiro中间简化了很多文件配置,但是主体内容基本一致

1.springboot整合shiro

1.1项目结构图

在这里插入图片描述

1.2访问流程

在这里插入图片描述

1.3项目内容

1.3.1配置类及pom文件

  • 项目启动类
@SpringBootApplication
@MapperScan("com.fyx.dao")//包扫描
public class Day0408SpringbootApplication {
    public static void main(String[] args) {
        SpringApplication.run(Day0408SpringbootApplication.class, args);
    }
}
  • ①首先创建springboot项目,在pom.xml文件中导入相关依赖。
<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.14</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.4.1</version>
        </dependency>

		<!--thymeleaf-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>com.github.theborakompanioni</groupId>
			<artifactId>thymeleaf-extras-shiro</artifactId>
			<version>2.0.0</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.62</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>5.1.47</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
  • ②application.properties
# 配置数据源
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql:///shiro
spring.datasource.druid.username=root
spring.datasource.druid.password=123@qwe
  • shiro的配置文件

在ssm项目中,shiro的组件创建在spring配置文件中,在springboot项目中,需要自己创建一个配置类

ShiroConfig类

@Configuration//等价于spring的配置文件
public class ShiroConfig {
    //    配置安全管理器
    @Bean("securityManager")
    public DefaultWebSecurityManager securityManager(Realm myRealm){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        return securityManager;
    }
    //  创建MyRealm对象
    @Bean(value = "myRealm")//依赖注入
    public Realm getRealm(CredentialsMatcher credentialsMatcher){
        MyRealm myRealm = new MyRealm();
        myRealm.setCredentialsMatcher(credentialsMatcher);
        return myRealm;
    }

    @Bean(value = "credentialsMatcher")//密码配置器
    public CredentialsMatcher getCredentialsMatcher(){
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashIterations(1024);//散列次数
        credentialsMatcher.setHashAlgorithmName("MD5");//使用MD5加密
        return credentialsMatcher;
    }
    //    配置过滤规则
    @Bean("shiroFilter")//shiro过滤
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/tologin");//路径
        shiroFilterFactoryBean.setSuccessUrl("/success.html");//访问成功后调转的路径
        HashMap<String, String> map = new HashMap<>();
        map.put("/index.html","anon");//
        map.put("/static/**","anon");
        map.put("/login","anon");
        map.put("/**","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }
    //    配置过滤器  相当于ssm项目中web.xml的给shiro配置过滤器
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean();
        filterRegistrationBean.setName("shiroFilter");
        filterRegistrationBean.setFilter(new DelegatingFilterProxy());

        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    }
    //使shiro标签库可以在thymeleaf中使用
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }
}

1.3.2html文件

springboot项目不支持jsp,只能使用html,要使用thymeleaf模板,需要导入依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  • login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/login" method="post">
    账号:<input type="text" name="username"/><br>
    密码:<input type="text" name="userpwd"/><br>
    <input type="submit" value="登陆"/>
    <input type="button" value="注册" onclick="location.href='regist'"/>
</form>
</body>
</html>
  • success.html
    在这个页面中需要使用shiro的标签,要在页面中引入shiro的标签,也要在pom.xml中引入依赖
		<dependency>
			<groupId>com.github.theborakompanioni</groupId>
			<artifactId>thymeleaf-extras-shiro</artifactId>
			<version>2.0.0</version>
		</dependency>
<!DOCTYPE html>
<html lang="en" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>成功页面</title>
</head>
<body>
成功 <h1>欢迎来到xxx班 尽情欢呼!</h1>
<shiro:hasPermission name="user:query">
    <a href="/user/query">查询所有用户</a><br>
</shiro:hasPermission>

<shiro:hasPermission name="user:update">
    <a href="/user/update">修改用户</a><br>
</shiro:hasPermission>

<shiro:hasPermission name="user:delete">
    <a href="/user/delete">删除用户</a><br>
</shiro:hasPermission>

<shiro:hasPermission name="user:insert">
    <a href="/user/insert">添加用户</a><br>
</shiro:hasPermission>

<shiro:hasPermission name="user:export">
    <a href="/user/export">导出用户</a><br>
</shiro:hasPermission>
</body>
</html>
  • un.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
无权访问
</body>
</html>

1.3.3后端类文件

  • dao层
    ①UserDao
public interface UserDao extends BaseMapper<User> {
      /**
     * 根据用户id查询该用户具有的权限
     * @param userid
     * @return
     */
    List<String> findPermissionByUserid(Integer userid);
}

②PermissionDao

public interface PermissionDao {
    /**
     * 根据userid查询用户权限
     */
    List<String> findAllPermissionByUserId(Integer userid);
}
  • entity层
    User
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer userid;
    private String username;
    private String userpwd;
    private String  sex;
    private String  address;
    private String  salt;//盐
}
  • service层
    ①UserService
public interface UserService {

    User selectByUsername(String username);
}

②UserServiceImpl

@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserDao userDao;

    @Override
    public User selectByUsername(String username) {
        //条件构造器
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);//相当于username=#{username}
        User user = userDao.selectOne(wrapper);
        return user;
    }
}
  • user的映射文件
<?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.fyx.dao.UserDao">

    <select id="findPermissionByUserid" resultType="String">
        select percode from user_role ur,role_permission rp, permission p
        where ur.roleid=rp.roleid and rp.perid=p.perid and ur.userid=#{userid}
    </select>
</mapper>
  • Controller层
    ①PageController
@Controller
public class PageController {
    @GetMapping("tologin")
    public String tologin(){
        return "login";
    }
}

②LoginController

@Controller
public class LoginController {

    @PostMapping("login")
    public String login(String username,String userpwd){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username,userpwd);
        try{
            subject.login(token);//开始认证
            return "success";
        }catch (Exception e){
            return "redirect:/tologin";
        }
    }
}

③UserController

@RestController
@RequestMapping("user")
public class UserController {
    @GetMapping("query")
    @RequiresPermissions("user:query")//当前Subject需要拥有某些特定的权限时,才能执行被该注解标注的方法。如果当前Subject不具有这样的权限,则方法不会被执行。
    public String query(){
        return "user:query";
    }
    @GetMapping("delete")
    @RequiresPermissions("user:delete")
    public String delete(){
        return "user:delete";
    }

    @GetMapping("update")
    @RequiresPermissions("user:update")
    public String update(){
        return "user:update";
    }

    @GetMapping("insert")
    @RequiresPermissions("user:insert")
    public String insert(){
        return "user:insert";
    }

    @GetMapping("export")
    @RequiresPermissions("user:export") //@Transcational
    public String export(){
        return "user:export";
    }
}
  • handler层

ExceptionController : 处理异常

@ControllerAdvice
public class ExceptionController {
    @ExceptionHandler(value = AuthorizationException.class)
    public String handler(){
        return "un";
    }
}
  • realm层

MyRealm类

public class MyRealm extends AuthorizingRealm {
    @Resource
    private UserService userService;
    @Resource
    private PermissionService permissionService;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //查询用户权限信息
        User user = (User)principalCollection.getPrimaryPrincipal();
        //通过userid查询对应用户所具有的权限
        List<String> userId = permissionService.findAllPermissionByUserId(user.getUserid());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //判断查询的权限集合是否有值
        if (userId.size()>0){
            //将权限添加到授权对象中
            info.addStringPermissions(userId);
        }
        return info;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取前台传的用户名
        String username = authenticationToken.getPrincipal().toString();
        User user = userService.selectByUsername(username);
        if (user!=null){
            ByteSource bytes = ByteSource.Util.bytes(user.getSalt());
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getUserpwd(),bytes,this.getName());
            return info;
        }
        return null;
    }
}
  • 测试
    在这里插入图片描述
    在这里插入图片描述

2.springboot整合shiro完全分离

前后端完成分离,后端返回给访问者的是json数据

该项目中有三个地方需要改造返回json数据:
1、认证成功或认证失败时
2、出现异常时,例如权限不足时
3、未登录访问时

  • ①创建返回的json数据格式的Result类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
    private Integer code;
    private String msg;
    private Object data;
}
  • ②改造Controller

将Controller层的@Controller都改成@RestController,将@ControllerAdvice改成@RestControllerAdvice

LoginController

@PostMapping("login")
    public Result login(String username, String userpwd){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token=new UsernamePasswordToken(username,userpwd);
        try {
            subject.login(token);//realm的认证功能
//getPrincipl()可以得到SimpleAuthenticationInfo中的数据
            Object user = subject.getPrincipal();
            return new Result(2000,"登陆成功",user);
        }catch (Exception e){
            return new Result(5000,"登陆失败",null);
        }
    }
  • ②改PageController

PageController

@RestController
public class PageController {
    @GetMapping("/tologin")
    public Result loginPage(){
        return new Result(5002,"请先登录",null);
    }
}
  • ExceptionController 异常处理类
@RestControllerAdvice
public class MyHandlerException {

    @ExceptionHandler(value = UnauthorizedException.class)
    public ResultunauthorizedException(){
        return new Result(5001,"权限不足",null);
    }
}
  • 测试
    在这里插入图片描述
    在这里插入图片描述
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值