实战:Springboot整合shiro实现权限控制实战

1.项目结构

在这里插入图片描述

2.pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wo</groupId>
    <artifactId>home_shiro_springboot</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

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

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</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>
        <!--shiro的包-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
        <!--JPA-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- swagger2 的依赖/自动生成接口文档以及自测的工具-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.8.0</version>
        </dependency>
    </dependencies>

</project>

3.application.yml

server:
  port: 8088
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql:///qf?useUnicode=true&characterEncoding=utf8&useSSL=false
  jpa:
    database: mysql
    show-sql: true
    generate-ddl: true
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml

4.config

4.1.ShiroConfig

@Configuration
public class ShiroConfig {



    //1.获取到我们的myrealm
    @Bean(name = "myRealm")
    public MyRealm myRealm(@Qualifier("hashedCredentialsMatcher")HashedCredentialsMatcher matcher){
        MyRealm myRealm = new MyRealm();
        myRealm.setAuthorizationCachingEnabled(false);
        myRealm.setCredentialsMatcher(matcher);
        return myRealm;
    }

    //2.声明securityManager
    @Bean(name = "defaultWebSecurityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("myRealm") MyRealm myRealm){
        //shiro核心
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        //在核心中设置我们自定义的realm
        defaultWebSecurityManager.setRealm(myRealm);

        return defaultWebSecurityManager;

    }

    //3.工厂
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager")DefaultWebSecurityManager defaultWebSecurityManager){

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //权限
        //声明没有权限的情况下走的接口名称
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");
//        //告诉shiro有用什么权限可以访问什么接口
        //如果不加注解不加map,默认没有权限控制
//         Map map = new HashMap<>();
//         map.put("/findAll","perms[user_findAll]");
//         map.put("/deleteById","perms[user_delete]");
//        //将访问接口的权限放置到shiroFileter中
//         shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;

    }

    //使用aop注解模式来使用权限
    //使用aop扫描包含shiro注解的类
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
    //将WebSecurityManager 交给spring aop来进行管理
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("defaultWebSecurityManager")DefaultWebSecurityManager defaultWebSecurityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 密码校验规则HashedCredentialsMatcher
     * 这个类是为了对密码进行编码的 ,
     * 防止密码在数据库里明码保存 , 当然在登陆认证的时候 ,
     * 这个类也负责对form里输入的密码进行编码
     * 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher
     */
    @Bean("hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //指定加密方式为MD5
        credentialsMatcher.setHashAlgorithmName("MD5");
        //加密次数
        credentialsMatcher.setHashIterations(1);
        credentialsMatcher.setStoredCredentialsHexEncoded(true);
        return credentialsMatcher;
    }

}

4.2.Swagger2Config(接口文档)

//标注当前工程是一个配置类
@Configuration
//开启swagger的配置
@EnableSwagger2
public class Swagger2Config {
    //将该Docket交给了spring中的ioc
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                // swagger进行包扫描,扫描你当前的controller层路径
                .apis(RequestHandlerSelectors.basePackage("com.wo.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("java-swagger")
                .description("swagger接入教程,简单好用")
                //服务条款网址
                .version("1.0")
                .build();
    }
}

5.controller

5.1PermissionExcepitonController

//控制器增强  异常捕获类
@ControllerAdvice
public class PermissionExcepitonController {
    //告诉控制器 捕捉什么类型的异常 以及对异常进行处理
    @ExceptionHandler(value = AuthorizationException.class)
    public String excepiton(){
        return "unauth";
    }
    @ExceptionHandler(value = ArithmeticException.class)
    public String urithmeticException(){
        return "error";
    }
}

5.2PersonController

@Controller
public class PersonController {

    @Autowired
    PersonService personService;

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

    @RequestMapping("/login")
    public String login(TbSysUser tbSysUser){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(tbSysUser.getLoginName(), tbSysUser.getPassword());
        try {
            subject.login(token);

        }catch (IncorrectCredentialsException ini){
            System.out.println(ini.getMessage());
        }
        if (subject.isAuthenticated()){
            return "redirect:findAll";
        }else{
            return "login";
        }
    }
    @RequestMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "login";
    }

    @RequiresPermissions(value = {"user_findAll"})
    @RequestMapping("/findAll")
    public ModelAndView findAll(){
        List<Person> list = personService.findAll();
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.addObject("list",list);
        modelAndView.setViewName("index");
        return modelAndView;
    }

    @RequiresPermissions(value = {"user_update"})
    @RequestMapping("/findById")
    public ModelAndView findById(@RequestParam ("id")int id){
        Person person = personService.findById(id);
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.addObject("person",person);
        modelAndView.setViewName("update");
        return modelAndView;
    }
    @RequiresPermissions(value = {"user_delete"})
    @RequestMapping("/deleteById")
    public String deleteById(@RequestParam ("id")int id){
        personService.deleteById(id);
        return "redirect:/findAll";
    }
    @RequiresPermissions(value = {"user_update"})
    @RequestMapping("/update")
    public String update(Person person){
        personService.update(person);
        return "redirect:/findAll";
    }
    @RequiresPermissions(value = {"user_update"})
    @RequestMapping("/goUpadatePage")
    public ModelAndView goUpadatePage(){
        Person person=new Person();
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.addObject("person",person);
        modelAndView.setViewName("update");
        return modelAndView;
    }
    @RequestMapping("/unauth")
    public String unauth(){
        return "unauth";
    }
}

6.dao和mapper

6.1 PersonDao

public interface PersonDao  extends JpaRepository<Person,Integer>{
}

6.2 TbSysPermissionDao

@Mapper
public interface TbSysPermissionDao {

    List<TbSysPermissions> findPermissonByLoginName(@Param("loginName") String loginName);
}

6.3 TbUserDao

@Mapper
public interface TbUserDao {

    TbSysUser login(@Param("loginName") String loginName);
}

6.4 TbPermissionMapper.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.wo.dao.TbSysPermissionDao">
    <resultMap id="BaseResult" type="com.wo.pojo.TbSysPermissions">

        <id property="permissionId" column="permission_id"></id>
        <result property="perName" column="per_name"></result>
    </resultMap>

    <select id="findPermissonByLoginName" resultMap="BaseResult">
        SELECT sp.per_name from tb_sys_user su,tb_sys_role sr,tb_sys_permission sp, tb_user_role ur,tb_role_permission rp
        where su.userid=ur.user_id
        and ur.role_id = sr.role_id
        and sr.role_id = rp.role_id
        and rp.permission_id = sp.permission_id
        and su.login_name=#{loginName};
    </select>
</mapper>

6.5 TbUserMapper.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.wo.dao.TbUserDao">
    <resultMap id="BaseResult" type="com.wo.pojo.TbSysUser">

        <id property="userid" column="userid"></id>
        <result property="loginName" column="login_name"></result>
        <result property="password" column="password"></result>
    </resultMap>

    <select id="login" resultMap="BaseResult">
        select * from tb_sys_user where login_name = #{loginName}
    </select>
</mapper>

7.pojo

7.1 Person

@Data
@Entity
@Table(name = "tb_person")
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private int age;
    private int is_marry;
    private String user_name;
    private int sex;
    private String address;
    @DateTimeFormat(pattern = "yyyy-MM-ss")
    private Date birthday;
}

7.2 TbSysPermissions

@Data
public class TbSysPermissions {

    private Integer permissionId;

    private String perName;
}

7.3 TbSysUser

@Data
public class TbSysUser {


    private Integer userid;

    private String loginName;

    private String password;
}

8.service

8.1 PersonService

public interface PersonService {

    public List<Person> findAll();

    public Person findById(int id);

    public void deleteById(int id);

    public void update(Person person);
}

8.2 PersonServiceImpl

@Service
public class PersonServiceImpl implements PersonService {

    @Autowired
    PersonDao personDao;

    @Override
    public List<Person> findAll() {
        return personDao.findAll();
    }

    @Override
    public Person findById(int id) {
        Optional<Person> byId = personDao.findById(id);
        if(byId.isPresent()){
            Person person=byId.get();
            return person;
        }
        return null;
    }

    @Override
    public void deleteById(int id) {
        personDao.deleteById(id);
    }

    @Override
    public void update(Person person) {
        personDao.saveAndFlush(person);
    }
}

9. shiro

MyRealm

@Component
public class MyRealm extends AuthorizingRealm {

    @Autowired
    TbUserDao tbUserDao;

    @Autowired
    TbSysPermissionDao tbSysPermissionDao;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        //获取到前端传输用户名
        String username = (String) principalCollection.getPrimaryPrincipal();
        //使用用户名查询该用户的权限
        List<TbSysPermissions> permissonByLoginName = tbSysPermissionDao.findPermissonByLoginName(username);
        //声明set进行去重
        HashSet<String> set=new HashSet<>();
        for (TbSysPermissions tb:permissonByLoginName) {
            set.add(tb.getPerName());
        }
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setStringPermissions(set);
        return simpleAuthorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获得到用户名
        String username = (String) authenticationToken.getPrincipal();
        //使用用户名查询密码
        TbSysUser user = tbUserDao.login(username);
        //不使用加盐加密
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, user.getPassword(), getName());
        //使用加盐加密
        //SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, user.getPassword(),ByteSource.Util.bytes("wang"), getName());
        return simpleAuthenticationInfo;
    }
}

10.SpringbootWangApplication

@SpringBootApplication
public class SpringbootWangApplication {
//
	public static void main(String[] args) {
		SpringApplication.run(SpringbootWangApplication.class, args);
	}

}

11.templates

11.1 error.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>您当前的操作有误,请稍后再试</h1>
</body>
</html>

11.2 index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<center>

    <h1>=========王沁狄==========</h1>
    <h2><a th:href="swagger-ui.html">接口页面-----<a href="/logout">退出登录</a></a></h2>

    <a th:href="@{/goUpadatePage}">新增</a>
    <table border="1">
        <tr>
            <th>序号</th>
            <th>ID</th>
            <th>姓名</th>
            <th>年龄</th>
            <th>性别</th>
            <th>生日</th>
            <th>婚姻</th>
            <th>地址</th>
            <th>操作</th>
        </tr>

        <tr th:each="person,p:${list}">
            <td th:text="${p.index+1}"></td>
            <td th:text="${person.id}"></td>
            <td th:text="${person.user_name}"></td>
            <td th:text="${person.age}"></td>
            <td>
                <span th:if="${person.sex eq 1}"></span>
                <span th:if="${person.sex eq 0}"></span>
            </td>
            <td th:text="${person.birthday}"></td>
            <td>
                <span th:if="${person.is_marry eq 1}">已婚</span>
                <span th:if="${person.is_marry eq 0}">未婚</span>
            </td>
            <td th:text="${person.address}"></td>

            <td>
                <a th:href="@{'deleteById?id='+${person.id}}">删除</a>
                <a th:href="@{'findById?id='+${person.id}}">修改</a>
            </td>
        </tr>
    </table>
</center>
</body>
</html>

11.3 login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<center>
    <form action="/login" method="post">
        用户名:<input type="text" name="loginName"><br>
        密码:<input type="password" name="password"><br>
        <input type="submit" value="提交">
    </form>
</center>
</body>
</html>

11.4 unauth.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>您没有权限,请联系管理员</h1>
</body>
</html>

11.5 update.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form th:action="@{/update}" th:method="post">
        <input th:type="hidden" th:name="id" th:value="${person.id}">
        姓名: <input th:type="text"  th:name="user_name" th:value="${person.user_name}"><br/>
        年龄: <input th:type="text" th:name="age" th:value="${person.age}"><br/>
        性别: <input th:type="text" th:name="sex"  th:value="${person.sex}"><br/>
        生日: <input th:type="datetime-local" th:name="birthday"  th:value="${person.birthday}"><br/>
        婚姻: <input th:type="text"  th:name="is_marry" th:value="${person.is_marry}"><br/>
        地址: <input th:type="text" th:name="address" th:value="${person.address}"><br/>
        <input th:type="submit" th:value="提交">
    </form>
</body>
</html>
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值