shiro学习(一)springboot 整合 shiro的基本配置

Spring Boot + Shiro + thymeleaf 整合,以及一些页面标签的使用

shiro的功能介绍以及一些特点之类的这里就不介绍了,百度下就ok了,这里只是介绍如何与spring boot进行整合。

后续还有一些关于shiro加密、多realm验证、缓存替换为redis等等。

springboot版本:

<version>1.5.20.RELEASE</version>
<!--spring的aop-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
		<!-- thymeleaf 模板引擎 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>net.sourceforge.nekohtml</groupId>
			<artifactId>nekohtml</artifactId>
		</dependency>
		<!--shiro与spring的整合依赖-->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.0</version>
		</dependency>
		<dependency>
			<groupId>com.github.theborakompanioni</groupId>
			<artifactId>thymeleaf-extras-shiro</artifactId>
			<version>1.2.1</version>
		</dependency>
		<!-- Shiro-redis插件 -->
		<dependency>
			<groupId>org.crazycake</groupId>
			<artifactId>shiro-redis</artifactId>
			<version>3.1.0</version>
		</dependency>

java代码:

ShiroConfig.java

package com.qw.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.qw.shiro.FilterChainDefinitionMapBuilder;
import com.qw.shiro.UserRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * shiro配置类
 */
@Configuration
public class ShiroConfig {

    @Autowired
    private UserRealm userRealm;

    @Autowired
    private FilterChainDefinitionMapBuilder mapBuilder;

    @Bean
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(userRealm);
        return defaultWebSecurityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        // 设置 SecurityManager
        bean.setSecurityManager(securityManager);
        // 设置登录页面的Url
        bean.setLoginUrl("/login/listPage");
        // 登录成功时访问的Url
        bean.setSuccessUrl("/admin/home/page/index");
        // 没有权限时访问的url
        bean.setUnauthorizedUrl("/login/unauthorizedUrl");
        bean.setFilterChainDefinitionMap(mapBuilder.buildFilterChainDefinitionMap());
        return bean;
    }

    //使用shiro页面标签
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

}
FilterChainDefinitionMapBuilder:从数据库中获取全部权限的url。
package com.qw.shiro;

import org.springframework.stereotype.Component;

import java.util.LinkedHashMap;

@Component
public class FilterChainDefinitionMapBuilder {

    //查询数据库中的所有url权限。权限必须要有顺序的写。
    public LinkedHashMap<String, String> buildFilterChainDefinitionMap(){
        /**
         * anon:匿名用户可访问
         * authc:认证用户可访问
         * user:使用rememberMe可访问
         * perms:对应权限可访问
         * role:对应角色权限可访问
         **/
        LinkedHashMap<String, String> filterMap = new LinkedHashMap<>();
        //静态资源
        filterMap.put("/jquery/**", "anon");
        filterMap.put("/lay-config/**", "anon");
        filterMap.put("/layui-v2.3.0/**", "anon");
        filterMap.put("/layui-v2.5.5/**", "anon");
        filterMap.put("/layui_extends/**", "anon");
        filterMap.put("/utils/**", "anon");
        filterMap.put("/wangEditorJS/**", "anon");
        //登陆的url
        filterMap.put("/login/login", "anon");

        //从数据库中查询出所有需要权限才可以访问的url。
        filterMap.put("/admin/home/page/index","perms[/admin/home/page/index]");
        filterMap.put("/admin/home/page/user","perms[/admin/home/page/user]");
        filterMap.put("/admin/home/page/role","perms[/admin/home/page/role]");

        filterMap.put("/**","authc");

        return filterMap;
    }
}
UserRealm:实现登陆用户的认证(即登陆)和鉴权(即授权)
package com.qw.shiro;

import com.qw.model.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 自定义Realm,自己注入bean进行获取用户权限信息
 */
@Slf4j
@Component
public class UserRealm extends AuthorizingRealm {

    //授权,即查询权限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //1. 从 PrincipalCollection 中来获取登录用户的信息,获取的是从认证,即登陆接口中保存的信息。
        User user = (User) principals.getPrimaryPrincipal();

        //2、通过用户信息去数据库查询其权限,也可以再认证的时候查询,保存再SimpleAuthenticationInfo 里面,在PrincipalCollection 中取出。
        //这里就直接写死了。
        //用户的角色信息
        Set<String> roleSet = new HashSet<>();
        roleSet.add("超级管理员");

        //用户的所有url权限信息
        Set<String> urlSet = new HashSet<>();
        urlSet.add("/admin/home/page/index");
        urlSet.add("/admin/home/page/role");

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(roleSet);
        info.addStringPermissions(urlSet);
        return info;
    }

    //认证,即登陆
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String)token.getPrincipal();  //得到用户名
        String password = new String((char[])token.getCredentials()); //得到密码

        log.info("username = {},password = {}",username,password);

        //根据登陆账号,查出数据库中的用户信息,这里我就不写了。
        User user = new User();
        user.setId(1L);
        user.setName("admin");
        user.setPassword("e10adc3949ba59abbe56e057f20f883e");
        if (user == null){
            throw new UnknownAccountException("用户不存在!");
        }

        //异常类型有:可以根据比对,自行抛出异常。
        //UnknownAccountException:用户不存在
        // IncorrectCredentialsException:若账户存在, 但密码不匹配, 则 shiro 会抛出 IncorrectCredentialsException 异常。
        // LockedAccountException 用户被锁定的异常 LockedAccountException
        // AuthenticationException 所有认证时异常的父类.

        //把用户信息存储,这里可以放入用户对象,可以方便上面的授权方法直接获取对象
        //shiro是对密码的比对,不会比对用户名。
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
        return info;
    }
}

controller

LoginController

package com.qw.controller;


import com.qw.utils.RspFailMessage;
import com.qw.utils.RspMessage;
import com.qw.utils.RspSuccessMessage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Api(tags = "登陆")
@Slf4j
@Controller
@RequestMapping("/login")
public class LoginController {

    @ApiOperation("登陆页面")
    @GetMapping("/listPage")
    public String listPage(){
        return "login";
    }

    @ResponseBody
    @ApiOperation("登陆")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "account", value = "账号", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "password", value = "密码", paramType = "query", dataType = "String")
    })
    @PostMapping("/login")
    public RspMessage loginIn(String account,String password) {
        UsernamePasswordToken token = new UsernamePasswordToken(account, password);

        //当前正在运行的主体,里面包含了,用户是否登陆、是否具有某种角色,具有某种权限等等。
        Subject subject = SecurityUtils.getSubject();
        try {
            System.out.println("用户是否登陆:"+subject.isAuthenticated());
            subject.login(token);//登陆
            System.out.println("用户是否登陆:"+subject.isAuthenticated());
        } catch (UnknownAccountException uae ) {
            //用户名不在系统中,显示错误信息?
            return new RspFailMessage("","用户或密码错误");
        } catch (IncorrectCredentialsException ice ) {
            //密码不匹配,请重试?
            return new RspFailMessage("","用户或密码错误");
        } catch (LockedAccountException lae ) {
            //该用户名的帐户被锁定-无法登录。给他们看信息?
            return new RspFailMessage("","账号被锁定,请联系管理员");
        } catch (AuthenticationException ae ) {
            //意外条件-错误?
            return new RspFailMessage("","账号不存在");
        }
        return new RspSuccessMessage();
    }

    @ApiOperation("登出")
    @GetMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "redirect:/login/listPage";
    }

    @ApiOperation("没有权限的页面")
    @GetMapping("/unauthorizedUrl")
    public String unauthorizedUrl(){
        return "unauthorized";
    }
}

HomeController

package com.qw.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Api(tags = "首页")
@Slf4j
@Controller
@RequestMapping("/admin")
public class HomeController {

    @ApiOperation("首页页面")
    @GetMapping("/home/page/index")
    public String index(){
        return "shiro/index";
    }

    @ApiOperation("用户页面")
    @GetMapping("/home/page/user")
    public String user(){
        return "shiro/user";
    }

    @ApiOperation("角色页面")
    @GetMapping("/home/page/role")
    public String role(){
        return "shiro/role";
    }
}

html页面

登陆页面由于是layui写的,这里就不写了,谁便写个ajax提交就可以了。

用户页面、角色页面、没有权限页面,就是一个单纯的html页面,没有什么内容,只是用来标识下,是否跳转了而已。

登陆成功跳转的首页:index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    首页
    <br/>
    <br/>
    <!--如果当前用户的角色不是超级管理员,就不显示它-->
    <shiro:hasRole name="超级管理员">
        <!--显示登陆用户在reaml中存入的信息,就是保存在 SimpleAuthenticationInfo 类里面的信息-->
        用户名称:<shiro:principal shiro:principal="username"></shiro:principal>
    </shiro:hasRole>
    <br/><br/>
    <shiro:hasPermission name="/admin/home/page/user">
        <a href="/admin/home/page/user">用户页面</a>
    </shiro:hasPermission>

    <br/>
    <br/>
    <!--如果当前用户没有这个权限,就不显示它-->
    <shiro:hasPermission name="/admin/home/page/role">
        <a href="/admin/home/page/role">角色页面</a>
    </shiro:hasPermission>

    <br/>
    <br/>
    <a href="/login/logout">登出</a>
</body>
</html>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值