【shiro】springboot整合shiro

springboot整合shiro,实现用户登录认证,权限校验及rememberMe

1.数据库准备

user 用户表

CREATE TABLE `user` (
  `id` bigint NOT NULL,
  `name` varchar(30) DEFAULT NULL,
  `pwd` varchar(35) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
  `rid` bigint DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

这里的密码是z3,经过MD5多次加盐后的结果

【shiro】springboot整合shiro_第1张图片

role 角色表

CREATE TABLE `role` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `desc` varchar(20) DEFAULT NULL,
  `realName` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

【shiro】springboot整合shiro_第2张图片

permissions 权限表

CREATE TABLE `permissions` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `info` varchar(20) NOT NULL,
  `desc` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

【shiro】springboot整合shiro_第3张图片

role_user 角色用户关系表

CREATE TABLE `role_user` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `uid` bigint NOT NULL,
  `rid` bigint NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

【shiro】springboot整合shiro_第4张图片

role_ps 角色权限关系表

CREATE TABLE `role_ps` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `rid` bigint NOT NULL,
  `pid` bigint NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

【shiro】springboot整合shiro_第5张图片

项目结构图

【shiro】springboot整合shiro_第6张图片

2.导包

<dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-spring-boot-web-starter</artifactId>
      <version>1.9.0</version>
    </dependency>

    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.0.5</version>
    </dependency>

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

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

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.20</version>
    </dependency>

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

    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-ehcache</artifactId>
      <version>1.9.0</version>
    </dependency>

    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.5</version>
    </dependency>

3.User实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private Long id;

    private String name;

    private String pwd;

    private Long rid;
}

4.UserMapper类

@Repository
public interface UserMapper extends BaseMapper<User> {

    // 通过用户名称获取角色名称
    @Select("select r.name from role r left join role_user ru on r.id = ru.rid left join user u on ru.uid = u.id where u.name = #{name}")
    List<String> getUserRoles(@Param(value = "name") String name);
    // 通过角色名称获取相关权限
    List<String> getPermissions(@Param(value = "roles") List<String> roles);
}

5.mapper.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.lkx.shiro.mapper.UserMapper">


    <select id="getPermissions" resultType="java.lang.String">
        SELECT p.info FROM permissions p LEFT JOIN role_ps rp ON p.id = rp.pid
        left join role r on r.id = rp.rid
        <where>
            <if test="roles != null and roles.size > 0">
                r.name in
                <foreach collection="roles" item="role" open="(" close=")" separator=",">
                    #{role}
                </foreach>
            </if>
        </where>

    </select>
</mapper>

6.service接口

public interface IUserService extends IService<User>{
    // 通过用户名查询用户信息
    User getUserInfoByName(String name);

    // 通过用户名称获取角色名称
    List<String> getUserRoles(String name);

    // 通过角色名称获取相关权限
    List<String> getPermissions(List<String> roles);
}

7.UserServiceImpl实现类

/**
 * @author likx
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Override
    public User getUserInfoByName(String name) {
        LambdaQueryWrapper<User> eq = new QueryWrapper<User>().lambda().eq(User::getName, name);
        return baseMapper.selectOne(eq);
    }

    @Override
    public List<String> getUserRoles(String name) {
        return this.baseMapper.getUserRoles(name);
    }

    @Override
    public List<String> getPermissions(List<String> roles) {
        return this.baseMapper.getPermissions(roles);
    }
}

8.自定义realm

@Component
@Slf4j
public class MyRealm extends AuthorizingRealm {

    @Autowired
    protected IUserService userService;


    /**
     * 自定义授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("自定义授权");

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 获取当前用户的角色
        List<String> userRoles = userService.getUserRoles(principalCollection.getPrimaryPrincipal().toString());

        log.info("roles:{}",userRoles);
        if (CollectionUtils.isNotEmpty(userRoles)) {
            authorizationInfo.addRoles(userRoles);
			// 获取用户拥有的权限
            List<String> permissions = userService.getPermissions(userRoles);
            log.info("permissions:{}",permissions);
            if (CollectionUtils.isNotEmpty(permissions)) {
                authorizationInfo.addStringPermissions(permissions);
            }
        }

        return authorizationInfo;
    }


    /**
     * 自定义登录认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        String name = authenticationToken.getPrincipal().toString();
        User user = userService.getUserInfoByName(name);

        if (Objects.nonNull(user)) {
            AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    authenticationToken.getPrincipal(),
                    user.getPwd(),
                    ByteSource.Util.bytes("salt"),
                    name);
            return authenticationInfo;
        }


        return null;
    }
}

9.shiro配置类

/**
 * @author likx
 */
@Configuration
public class ShiroConfig {
    @Autowired
    private MyRealm myRealm;

    /**
     * 配置securityManage
     * @return
     */
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager() {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        // 加密对象
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

        // md5加密
        hashedCredentialsMatcher.setHashAlgorithmName("md5");

        // 迭代加密次数
        hashedCredentialsMatcher.setHashIterations(3);

        myRealm.setCredentialsMatcher(hashedCredentialsMatcher);

        manager.setRememberMeManager(rememberMeManager());

        // 使用自定义realm
        manager.setRealm(myRealm);

        return manager;
    }

    /**
     * rememberCookie生成
     * @return
     */
    public SimpleCookie rememberCookie() {
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(30*24*60*60);
        return cookie;
    }

    /**
     * rememberMeManager 生成
     * @return
     */
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberCookie());
        cookieRememberMeManager.setCipherKey("1234567890987654".getBytes());
        return cookieRememberMeManager;
    }

    @Bean
    public DefaultShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();

        // 设置不认证可访问的资源
        definition.addPathDefinition("/myController/userLogin","anon");
        // 登录过滤
        definition.addPathDefinition("/login","anon");
        // 登出过滤
        definition.addPathDefinition("/logout","logout");
        // 设置需要登录认证的拦截范围
        definition.addPathDefinition("/**","authc");
        definition.addPathDefinition("/**","user");

        return definition;
    }

    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }
}

10.controller类

@Controller
@RequestMapping("/myController")
@Slf4j
public class MyController {

    @GetMapping("/userLogin")
    public String userLogin(@RequestParam(value = "name") String name,
                            @RequestParam(value = "pwd") String pwd,
                            @RequestParam(name = "rememberMe",defaultValue = "false") Boolean rememberMe,
                            HttpSession session) {
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken usernamePasswordToken = new UsernamePasswordToken(name, pwd,rememberMe);
        try {
            subject.login(usernamePasswordToken);
            session.setAttribute("user",name);
            log.info("登录成功");
            return "index";
        } catch (Exception e) {
            e.printStackTrace();
            log.info("登录失败");
            return "登录失败";
        }
    }

    @GetMapping("/loginRm")
    public String login(HttpSession session) {
        Object user = session.getAttribute("user");
        log.info("记住我登录:{}",user.toString());
        return "index";
    }

    /**
     * 登录认证角色验证
     */
    @RequiresRoles("admin")
    @GetMapping("/userLoginRoles")
    @ResponseBody
    public String userLoginRoles() {
        log.info("登录认证角色验证");
        return "验证角色成功";
    }
    /**
     * 登录认证权限验证
     */
    @GetMapping("/userLoginPermissions")
    @RequiresPermissions("user:delete")
    @ResponseBody
    public String userLoginPermissions() {
        log.info("登录认证权限验证");
        return "验证权限成功";
    }

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

11.权限异常处理

@ControllerAdvice
public class PermissionsException {

    @ResponseBody
    @ExceptionHandler(UnauthorizedException.class)
    public String unauthorizedException(Exception e) {
        return "无权限";
    }

    @ResponseBody
    @ExceptionHandler(AuthorizationException.class)
    public String authorizationException(Exception e) {
        return "权限认证失败";
    }
}

12.项目配置


mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/*.xml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/shirodb?charterEncoding=utf-8&useSSL=false
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
shiro:
  loginUrl: /myController/login
server:
  port: 8081

13.启动类

@SpringBootApplication
@MapperScan("com.lkx.shiro.mapper")
public class ShiroApplication {
    public static void main(String[] args) {
        SpringApplication.run(ShiroApplication.class,args);
    }
}

14.前端页面

index.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>
head>

<body>
<h1>Shiro登录成功h1>
<br>
登录用户为:<span th:text="${session.user}">span>
<br>
<a href="/logout">登出a>
<br>
<a shiro:hasRole="admin" href="/myController/userLoginRoles">测试授权a>
<br>
<a shiro:hasPermission="user:delete" href="/myController/userLoginPermissions">测试权限a>
body>


html>

login.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页title>
head>

<body>
<h1>Shiro登录认证h1>
<br>
<form  action="/myController/userLogin">
    <div>用户名: <input type="text" name="name" value="">div>
    <div>密码: <input type="password" name="pwd" value="">div>
    <div>记住我: <input type="checkbox" name="rememberMe" value="true">div>
    <div><input type="submit" value="登录">div>
form>
body>


html>

你可能感兴趣的:(shiro,spring,boot,java,spring,shiro)