Spring-Boot整合Shiro

本文源码地址:https://github.com/jonssonyan/spring-demo/tree/master/springboot-shiro

在Spring Boot中集成Shiro进行用户的认证过程主要可以归纳为以下三点:

  1. 定义一个ShiroConfig,然后配置SecurityManager Bean,SecurityManager为Shiro的安全管理器,管理着所有Subject;
  2. 在ShiroConfig中配置ShiroFilterFactoryBean,其为Shiro过滤器工厂类,依赖于SecurityManager;
  3. 自定义Realm实现,Realm包含doGetAuthorizationInfo()doGetAuthenticationInfo()方法,因为本文只涉及用户认证,所以只实现doGetAuthenticationInfo()方法。

引入依赖

		<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.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.4.1</version>
        </dependency>

ShiroConfig

@Configuration
public class ShiroConfig {
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultSecurityManager") DefaultSecurityManager defaultSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultSecurityManager);
        // 添加shiro内置过滤器
        /*
            anon:无参,开放权限,可以理解为匿名用户或游客
            authc:无参,需要认证
            logout:无参,注销,执行后会直接跳转到shiroFilterFactoryBean.setLoginUrl(); 设置的 url
            authcBasic:无参,表示 httpBasic 认证
            user:无参,表示必须存在用户,当登入操作时不做检查
            ssl:无参,表示安全的URL请求,协议为 https
            perms[user]:参数可写多个,表示需要某个或某些权限才能通过,多个参数时写 perms["user, admin"],当有多个参数时必须每个参数都通过才算通过
            roles[admin]:参数可写多个,表示是某个或某些角色才能通过,多个参数时写 roles["admin,user"],当有多个参数时必须每个参数都通过才算通过
            rest[user]:根据请求的方法,相当于 perms[user:method],其中 method 为 post,get,delete 等
            port[8081]:当请求的URL端口不是8081时,跳转到schemal://serverName:8081?queryString 其中 schmal 是协议 http 或 https 等等,serverName 是你访问的 Host,8081 是 Port 端口,queryString 是你访问的 URL 里的 ? 后面的参数
         */
        Map<String, String> map = new LinkedHashMap<>();
        // 设置访问页面需要的权限
        map.put("/user/add", "perms[user:add]");
        map.put("/user/update", "perms[user:update]");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        // 设置转到登陆界面
        shiroFilterFactoryBean.setLoginUrl("/toLogin");
        // 设置没有权限跳转的页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
        return shiroFilterFactoryBean;
    }

    @Bean
    public DefaultWebSecurityManager defaultSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(userRealm);
        return defaultWebSecurityManager;
    }

    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }
}

UserRealm

public class UserRealm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行授权");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 设置权限。这里只要登陆的用户都会执行下面这段代码,实际开发中,这里的权限应该从数据库中获取
        info.addStringPermission("user:add");
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行认证");
        // username,password从数据库中获取,这里为了方便在代码中写死
        String username = "admin";
        String password = "123";
        // 前端传来的用户名密码从token中获取
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        // 用户名认证
        if (!token.getUsername().equals(username)) {
            return null; // 用户名不正确,抛出异常UnknownAccountException
        }
        // 密码认证,shiro做,加密了
        return new SimpleAuthenticationInfo("", password, "");
    }
}

Controller

@Controller
public class MyController {
    @RequestMapping(value = {"/", "/index"})
    public String login() {
        return "login";
    }

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

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

    @RequestMapping("/toLogin")
    public ModelAndView toLogin(@RequestParam String username, @RequestParam String password, ModelAndView modelAndView) {
        // 获取当前用户subject
        Subject subject = SecurityUtils.getSubject();
        // 封装用户对象
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            subject.login(token); // 执行登陆操作
            modelAndView.setViewName("index");
            return modelAndView;
        } catch (UnknownAccountException u) { // 捕获用户名是否正确的异常
            modelAndView.addObject("msg", "用户名错误");
        } catch (IncorrectCredentialsException i) { // 密码是否正确的异常
            modelAndView.addObject("msg", "密码错误");
        }
        modelAndView.setViewName("login");
        return modelAndView;
    }

    @RequestMapping("/noAuth")
    @ResponseBody
    public String noAuth() {
        return "你尚未拥有权限";
    }
}

前端页面

前端使用的thymeleaf模板引擎

login.html

登录页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
<h1 th:text="${msg}"></h1>
<form method="post" th:action="@{/toLogin}">
    <input type="text" name="username" placeholder="请输入用户名">
    <input type="password" name="password" placeholder="请输入密码">
    <input type="submit" value="登陆">
</form>
</body>
</html>

index.html

后台主页

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>hello shiro</h1>
<a th:href="@{user/add}">add</a>
<a th:href="@{user/update}">update</a>
</body>
</html>

add.html

添加页面,需要有添加权限

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>add</title>
</head>
<body>
<h1>add</h1>
</body>
</html>

update.html

修改页面,需要有修改权限

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>update</title>
</head>
<body>
<h1>update</h1>
</body>
</html>

测试

登录

后台页面

代码中值赋予user角色添加的权限,所以当我们点击add按钮时可用,点击update按钮时不可用

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值