权限shiro与thymeleaf整合

javaweb的登录拦截请求,用拦截器也可以实现,但是得需要大量的代码。
使用springSecurity和shiro都可以实现同样的效果,下面来介绍一下shiro实现登录权限控制。

百度百科:
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

下面来做一些简单的例子,只是实现部分功能,其他的内容具体问题具体分析吧。

工具:idea2019
框架:springboot
前端引擎:thymeleaf

首先新建一个web项目导入maven依赖:

<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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
		<!--导入shiro依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <!--mysql数据库的包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.1</version>
        </dependency>
		<!--为了实现shiro与thymeleaf的整合的包-->
        <!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
    </dependencies>

导入依赖之后开始进行配置
application.yml
这些是最基本的配置 关闭thymeleaf的缓存,配置mybatis,连接数据库,端口

spring:
  thymeleaf:
    cache: false
  datasource:
    username: root
    password: 123
    url: jdbc:mysql://localhost:3306/ssmbuild?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
mybatis:
  type-aliases-package: com.pojo
  mapper-locations: classpath:mapper/*.xml
server:
  port: 8081

springboot的基本注解在这里就不说了。主要说一下shiro的配置。
三个核心组件:Subject, SecurityManagerRealms.
Subject就是当前操作的用户,
SecurityManager 是管理所有用户的安全操作,
Shiro会从应用配置的Realm中查找用户及其权限信息。


1.UserRealm是自定义的然后将其交给spring容器去管理
2.调用getDefaultWebSecurityManager这个方法来创建默认的权限管理者
3.调用getShiroFilterFactoryBean的构造函数来实例化一个过滤器
我们具体的权限设置也是在这里设置的。

public class UserRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //System.out.println("doGetAuthorizationInfo");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission("user:add");
        Subject thisUser = SecurityUtils.getSubject();
        //拿到User对象
        User currentUser = (User)thisUser.getPrincipal();
        //设置权限   从数据库中读取来设置
        info.addStringPermission(currentUser.getPrems());
        return info;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        User user = userService.searchByName(token.getUsername());
        System.out.println(user);
        if(user == null){
            return null;
        }
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.setAttribute("loginUser",user);
        //密码认证
        //传递user在授权中使用
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }
}
@Configuration
public class ShiroConfig  {
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager s){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(s);
        //添加内置过滤器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //开始授权

        filterChainDefinitionMap.put("/user/add","perms[user:add]");   //
        filterChainDefinitionMap.put("/user/update","perms[user:update]");   //
        filterChainDefinitionMap.put("/user/*","authc");
//        filterChainDefinitionMap.put("/user/update","authc");
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        //设置登录的请求
        bean.setLoginUrl("/login");
        bean.setUnauthorizedUrl("/noauth");

        return bean;
    }


    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userR){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(userR);
        return defaultWebSecurityManager;
    }
    //自定义的认证和授权 需要自己配置
    @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }

    //整合ShiroDialect  thymeleaf
    @Bean
    public ShiroDialect getShiroDialect(){
        return  new ShiroDialect();
    }


}

下面写一个controller来进行测试

@Controller
public class MyController {
    //因为
    @RequestMapping({"/","/index"})
    public String toIndex(Model model){
        model.addAttribute("msg", "one");
        return "/index2";
    }

    @RequestMapping("/user/add")
    public String add(Model model){
        return "/user/add";
    }
    @RequestMapping("/user/update")
    public String update(Model model){
        return "/user/update";
    }

    @RequestMapping("/login")
    public String toLogin(String username,String password,Model model){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            subject.login(token);
            //登录成功返回首页
            return "/index2";
        } catch (UnknownAccountException e) {
            model.addAttribute("msg","user is undefined");
            return "/login";
        } catch (IncorrectCredentialsException e){
            model.addAttribute("msg","password is unkown");
            return "/login";
        }
    }
    @RequestMapping("/noauth")
    @ResponseBody
    public String unauthorized(){
        //没有权限无法访问
        return "unauthorized";
    }
}

我们可以看到在controller中用SecurityUtils.getSubject()来获取了当前操作对象
然后调用login()方法来进行登录。具体的验证是由shiro去做的。如果是用拦截器来写的话
代码起码要翻一倍吧。(还可能有bug,如果让我写bug可能是改不完的,好尴尬)

下面贴上我在数据库设置的权限表
name和password就不说了。perms这个字段就是shiro用来拿这个去验证的
这里要注意这个权限按照常理来说是不可能为空的,这是我建表的失误。

拿这段代码为例

//第一个参数是路径,第二个参数是设置过滤权限
filterChainDefinitionMap.put("/user/add","perms[user:add]");

第一个参数是路径,第二个参数是设置过滤权限
也就是说访问add请求的时候你必须携带一个add权限否则无法访问。

最牛逼的地方啊,我觉得就是shiro和thymeleaf整合的地方。(我都惊呆了原来还可以这样)
看下html

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

<h1>首页</h1>

    <p th:text="${msg}"></p>
<div th:if="${session.loginUser == null}">
    <a th:href="@{/login}">登录</a>
</div>

<div shiro:hasPermission="user:add">
    <a th:href="@{/user/add}">add</a>
</div>
<div shiro:hasPermission="user:update">
    <a th:href="@{/user/update}">update</a>
</div>
</body>
</html>

如果 shiro:hasPermission="user:add"修饰在div上就可以直接控制该div根据权限是否显示。

这样就可以跑起来了,而这些代码只不过是可以小小的感觉一下shiro的作用。
如果想把登录写的更完善的话就需要罗列更多的代码。
了解来说的话,这样就差不多了,如果用到了可以再深究一下。
建议多看些数据结构和算法,这些插件和框架看看说明书找找资料就可以配置的,
但是,算法这个东西,不会就是不会啊!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值