springboot整合shiro安全认证框架

首先搭建一个简单的测试环境

  1. 搭建一个springboot 项目
  2. 引入依赖,主要是web starter shiro(安全认证) 和thymeleaf(简单的页面构建),这里不做数据层的查询,所以不引入数据库相关的。
 <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>
            <scope>test</scope>
        </dependency>

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

        <!--引入shrio-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.5.3</version>
        </dependency>
        
    </dependencies>
  1. 页面的构建,目录如下:
    在这里插入图片描述
    首页入口
    helloword.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>首页</h1>
<p th:text="${msg}"></p>
<hr>
<p><a href="add">add</a> | <a href="update">update</a></p>

</body>
</html>

点击add/update 接口的调用,将在这两个接口加入认证
add.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>添加</title>
</head>
<body>
    <h1 th:text="${msg}"></h1>
</body>
</html>

update.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>更新</title>
</head>
<body>
    <h1 th:text="${msg}"></h1>
</body>
</html>

点击接口如果没有登录,将跳转到登录页面
login/loginuser.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
    <h1>登录</h1>
    <p style="color: red" th:text="${msg}"></p>
    <form action="/login/loginInfo">
        <p>用户名:<input type="text" name="username"></p>
        <p>密码:<input type="text" name="password"></p>
        <input type="submit">
    </form>
</body>
</html>
  1. 写一个controller,给页面提供接口
@Controller
@RequestMapping("/login")
public class LoginController {

    @GetMapping("/index")
    public String gotoIndex(Model model) {

        model.addAttribute("msg","hello shiro");
        return "helloword";
    }

    @GetMapping("/add")
    public String add(Model model, HttpServletRequest request) {
        model.addAttribute("msg","添加成功!!!");
        HttpSession session = request.getSession();
        Object user_session = session.getAttribute("USER_SESSION");
        return "add";
    }

    @GetMapping("/update")
    public String update(Model model) {
        model.addAttribute("msg","更新成功!!!");
        return "update";
    }

    @GetMapping("/tologin")
    public String tologin(Model model) {

        return "login/loginuser";
    }
}

shiro讲解

在概念层,Shiro 架构包含三个主要的理念:Subject,SecurityManager和 Realm。下面的图展示了这些组件如何相互作用,我们将在下面依次对其进行描述。
在这里插入图片描述

  • Subject:当前用户,Subject
    可以是一个人,但也可以是第三方服务、守护进程帐户、时钟守护任务或者其它–当前和软件交互的任何事件。

  • SecurityManager:管理所有Subject,SecurityManager 是 Shiro
    架构的核心,配合内部安全组件共同组成安全伞。 Realms:用于进行权限信息的验证,我们自己实现。Realm 本质上是一个特定的安全

  • Realm:它封装与数据源连接的细节,得到Shiro 所需的相关的数据。在配置 Shiro
    的时候,你必须指定至少一个Realm来实现认证(authentication)和/或授权(authorization)。

编写Shiro配置类

首先要有一个配置类 ShiroConfig,里面提供一些bean,ShiroFilterFactoryBean,DefaultWebSecurityManager,Realm;我们先搭建一个Realm,这个类主要做认证和授权

/**
 * @author ojj
 * @title: MyRealm
 * @projectName test
 * @description:
 * @date 2021/12/31 10:17
 */
public class MyRealm extends AuthorizingRealm {

    /**
     * 授权 角色
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了授权");
        return null;
    }

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

        System.out.println("执行了认证");
        String name = (String)authenticationToken.getPrincipal();
        System.out.println("用户:"+name);
        //模拟从数据库中获取用户登录信息
        String username = "sb";
        String password = "123456";

        if (!username.equals(name)){
            return null;
        }

        return new SimpleAuthenticationInfo(name,password,"");
    }
}

ShiroConfig

@Configuration
public class ShiroConfig {

    //ShiroFilterFactoryBean
    @Bean()
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        //不拦截的接口
        filterChainDefinitionMap.put("/login/loginInfo","anon");
        filterChainDefinitionMap.put("/login/index","anon");
        //需要认证的接口
        //filterChainDefinitionMap.put("/login/add","authc");
        //filterChainDefinitionMap.put("/login/update","authc");
        //其余接口一律拦截
        //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
        filterChainDefinitionMap.put("/**","authc");
        
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        //认证不通过 跳转登录页面
        shiroFilterFactoryBean.setLoginUrl("/login/tologin");

        return shiroFilterFactoryBean;
    }

        //DefaultWebSecurityManager
    @Bean("securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("realm") Realm realm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

        defaultWebSecurityManager.setRealm(realm);
        return defaultWebSecurityManager;
    }

    //ShiroRealm
    @Bean("realm")
    public Realm getRealm(){
        return new MyRealm();
    }

}

在Controller添加一个登录的接口

 @GetMapping("/loginInfo")
    public String login(String username, String password,Model model) {

        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        try {
            //登录
            subject.login(token);
            return "helloword";

        }catch (UnknownAccountException e) {

            model.addAttribute("msg","用户不存在");
            return "login/loginuser";
        } catch (IncorrectCredentialsException e) {

            model.addAttribute("msg","密码错误");
            return "login/loginuser";
        }


    }

测试

在这里插入图片描述
点add,没登录的情况下,会跳转到登录页面
在这里插入图片描述
登录成功后,会返回一个session,之后点击add/update可以正常访问了
在这里插入图片描述

添加角色权限

比如说某个接口需要有经理级别才能使用,这时需要改造Realm中有另一个方法doGetAuthorizationInfo。

/**
 * @author ojj
 * @title: MyRealm
 * @projectName test
 * @description:
 * @date 2021/12/31 10:17
 */
public class MyRealm extends AuthorizingRealm {

    /**
     * 授权 角色
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了授权");
        //获取用户名字
        String name = (String) principalCollection.getPrimaryPrincipal();
        //使用name从数据库获取用户角色和权限
        String role = "admin";
        String permission = "test";
        //添加角色 权限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRole(role);
        simpleAuthorizationInfo.addStringPermission(permission);


        return simpleAuthorizationInfo;
    }

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

        System.out.println("执行了认证");
        String name = (String)authenticationToken.getPrincipal();
        System.out.println("用户:"+name);
        //模拟从数据库中获取用户登录信息
        String username = "sb";
        String password = "123456";

        if (!username.equals(name)){
            return null;
        }
        //name 可以上面的授权方法获取
        //password 用来比对密码
        //realmName
        return new SimpleAuthenticationInfo(name,password,"");
    }
}

然后哪些需要角色或权限的接口上加上注解@RequiresRoles @RequiresPermissions,shiro会自动去比对是否符合访问要求,如下 @RequiresRoles(“admin2”) 是访问不成功的,因为用户绑定了admin(伪代码写死),可以使用@RequiresPermissions(“test:update”)来设置多种权限。

@RequiresRoles("admin2")
    @GetMapping("/add")
    public String add(Model model, HttpServletRequest request) {
        model.addAttribute("msg","添加成功!!!");
        HttpSession session = request.getSession();
        Object user_session = session.getAttribute("USER_SESSION");
        return "add";
    }

    @RequiresPermissions("test")
    @GetMapping("/update")
    public String update(Model model) {
        model.addAttribute("msg","更新成功!!!");
        return "update";
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值