Shiro实现用户认证

SpringBoot与Shiro整合实现用户认证

Shiro的核心API

  • Subject:用户主体(把操作交给Security Manager)
  • SecurityManager:安全管理器(关联Realm)
  • Realm:Shiro连接数据的桥梁

整合

修改pom.xml

<!-- shiro与springboot整合依赖 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

自定义Realm类

package com.example.demo_shiro.shiro;

/**
 * 自定义Realm
 */
public class UserRealm extends AuthorizingRealm {
    /**
     * 执行授权逻辑
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行授权逻辑");
        return null;
    }

    /**
     * 执行认证逻辑
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行认证逻辑");
        return null;
    }
}

编写Shiro配置类

package com.example.demo_shiro.shiro;

@Configuration
public class ShiroConfig {

    /**
     * 创建ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        // 添加Shiro内置过滤器
        /**
         * Shiro内置过滤器,可以实现权限相关的拦截器
         *  常用的过滤器:
         *      anon:无需认证(登陆)可以访问
         *      authc:必须认证才可以访问
         *      user:如果使用rememberMe的功能,可以直接访问
         *      perms:该资源必须得到资源权限才可以访问
         *      role:该资源必须得到角色权限才可以访问
         */
        Map<String,String> filterMap = new LinkedHashMap<>();
        filterMap.put("/add", "anon");
        filterMap.put("/update", "authc");
        filterMap.put("/login","anon");
//        filterMap.put("/*", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        // 修改登陆的页面
        shiroFilterFactoryBean.setLoginUrl("/toLogin");

        return shiroFilterFactoryBean;
    }
    /**
     * 创建DefaultWebSecurityManager
     */
    @Bean("securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        // 关联userRealm
        defaultWebSecurityManager.setRealm(userRealm);
        return defaultWebSecurityManager;
    }
    /**
     * 创建Realm
     */
    @Bean("userRealm")
    public UserRealm getRealm() {
        return new UserRealm();
    }
}

使用Shiro内置过滤器实现页面拦截

  • Shiro内置过滤器,可以实现权限相关的拦截器
    的过滤器:
    • anon:无需认证(登陆)可以访问
    • authc:必须认证才可以访问
    • user:如果使用rememberMe的功能,可以直接访问
    • perms:该资源必须得到资源权限才可以访问
    • role:该资源必须得到角色权限才可以访问

设计登陆页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>登陆页面</title>
</head>
<body>
登陆
<h3 th:text="${msg}" style="color: red;"></h3>
<form method="post" action="login">
    用户名 <input type="text" name="name">
    密码 <input type="password" name="password">
    <button type="submit">登陆</button>
</form>
</body>
</html>

实现用户认证(登陆)操作

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

    @RequestMapping("/login")
    public String login(String name, String password, Model model) {
        /**
         * 使用Shiro编写认证操作
         */
        //1.获取Subject
        Subject subject = SecurityUtils.getSubject();
        //2.封装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(name, password);
        //3.执行登陆方法
        try {
            subject.login(token);
            //登陆成功
            return "redirect:/hello";
        } catch (UnknownAccountException e) {
//            登陆失败:用户名不存在
            e.printStackTrace();
            model.addAttribute("msg", "用户名不存在");
            //重定向消息就带不过去,所以这里就直接跳转了
            return "login";
        } catch (IncorrectCredentialsException e) {
            // 登陆失败:密码错误
            model.addAttribute("msg", "密码错误");
            return "login";
        }
    }

编写Realm的判断逻辑

package com.example.demo_shiro.shiro;

/**
 * 自定义Realm
 */
public class UserRealm extends AuthorizingRealm {
    /**
     * 执行授权逻辑
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行授权逻辑");
        return null;
    }

    /**
     * 执行认证逻辑
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行认证逻辑");
        //假设数据库中的数据如下
        String name = "name";
        String password = "123";

        // 编写shiro判断逻辑,判断用户名和密码
        // 1.判断用户名
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        if (!name.equals(token.getUsername())) {
            //用户名不存在,shiro底层会抛出UnknownAccountException
            return null;
        }
        // 2.判断密码
        return new SimpleAuthenticationInfo("",password,"");
    }
}

整合Mybatis

配置数据源

spring.datasource.dirverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=root

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

mybatis.type-aliases-package=com.example.domain

编写Mapper接口

com.example.mapper

SpringBoot与Shiro整合实现用户授权

使用Shiro内置过滤器拦截资源

ShiroConfig.java

// 授权过滤器
        //注意:当授权拦截后,shiro会自动跳转到未授权页面
        filterMap.put("/add", "perms[user:add]");
        // 设置未授权提示页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");

完成Shiro授权

UserRealm.java

@Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行授权逻辑");
        // 给资源进行授权
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        
        // 添加资源的授权字符串
        info.addStringPermission("user:add");
        
        
        return null;
    }

附录

ShiroConfig与UserRealm代码

ShiroConfig

package com.example.demo_shiro.shiro;

@Configuration
public class ShiroConfig {

    /**
     * 创建ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        // 添加Shiro内置过滤器
        /**
         * Shiro内置过滤器,可以实现权限相关的拦截器
         *  常用的过滤器:
         *      anon:无需认证(登陆)可以访问
         *      authc:必须认证才可以访问
         *      user:如果使用rememberMe的功能,可以直接访问
         *      perms:该资源必须得到资源权限才可以访问
         *      role:该资源必须得到角色权限才可以访问
         */
        Map<String,String> filterMap = new LinkedHashMap<>();
        filterMap.put("/add", "anon");
        filterMap.put("/update", "authc");
        filterMap.put("/login","anon");

        // 授权过滤器
        //注意:当授权拦截后,shiro会自动跳转到未授权页面
        filterMap.put("/add", "perms[user:add]");
        filterMap.put("/update", "perms[user:update]");
        // 设置未授权提示页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

        // 修改登陆的页面
        shiroFilterFactoryBean.setLoginUrl("/toLogin");

        return shiroFilterFactoryBean;
    }
    /**
     * 创建DefaultWebSecurityManager
     */
    @Bean("securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        // 关联userRealm
        defaultWebSecurityManager.setRealm(userRealm);
        return defaultWebSecurityManager;
    }
    /**
     * 创建Realm
     */
    @Bean("userRealm")
    public UserRealm getRealm() {
        return new UserRealm();
    }
}

UserRealm.java

package com.example.demo_shiro.shiro;

/**
 * 自定义Realm
 */
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    /**
     * 执行授权逻辑
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行授权逻辑");
        // 给资源进行授权
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        // 添加资源的授权字符串
        //info.addStringPermission("user:add");

        // 到数据库查询当前登陆用户的授权字符串
        // 获取当前用户
        Subject subject = SecurityUtils.getSubject();
        User user = (User)subject.getPrincipal();
        User dbUser = userService.findById(user.getId());

        info.addStringPermission(dbUser.getAuthCodeString());

        return info;
    }

    /**
     * 执行认证逻辑
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行认证逻辑");

        // 编写shiro判断逻辑,判断用户名和密码
        // 1.判断用户名
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        User user = userService.findByName(token.getUsername());
        //假设数据库中的数据如下
        if (!("jack".equals(token.getUsername())||"rose".equals(token.getUsername())||"person".equals(token.getUsername()))) {
            //用户名不存在,shiro底层会抛出UnknownAccountException
            return null;
        }
        // 2.判断密码
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }
}

猜你喜欢

转载自www.cnblogs.com/codeclock/p/12093633.html