Spring Boot 与Shrio整合

2019-06-10  本文已影响0人  過眼云烟

分析Shrio的核心API

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

Spring Boot整合Shiro

(1) 导入依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0></version>
<dependency/>

(2)自定义Realm类

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * 自定义Realm
 */
public class UserRealm extends AuthorizingRealm {
    /**
     * 执行授权逻辑
     * @param principalCollection
     * @return
     */
        //@Qualifier("userRealm")将userRealm注入当前类
    @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("执行认证逻辑");
        return null;
    }
}

(3)编写Shiro配置类(*)
建立shiro的配置类

/**
 * shiro配置类
 */
@Configuration
public class ShiroConfig {
    /**
     * 创建ShiroFilterFactoryBean
     */
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        return shiroFilterFactoryBean;

    }


    /**
     * 创建DefaultWebSecurityManager
     */
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        //@Qualifier("userRealm")将userRealm注入当前类
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /**
     * 创建Realm
     */
    @Bean
    public UserRealm getRealm(){
        return new UserRealm();
    }

(4) 使用Shiro内置过滤器实现页面拦截,在ShiroConfig中配置

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

    }

UserController中设置登录

    @PostMapping (value = "/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:getinfo";
        } catch (UnknownAccountException e) {   //UnknownAccountException shiro用户名不存在抛异常
           // e.printStackTrace();
            //登录失败
            model.addAttribute("msg","用户名不存在");
            return "login";
        }catch (IncorrectCredentialsException e) {
            //e.printStackTrace();
            //登录失败
            model.addAttribute("msg","密码错误");
            return "login";
        }

在UserRealm中,执行认证逻辑中,编写登录逻辑

    /**
     * 执行认证逻辑
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行认证逻辑");
        //假设数据库的用户名和密码  模拟数据库
        String name = "liwei";
        String password = "123456";
        //编写shiro判断逻辑,判断用户名和密码
        //1.判断用户名
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        if(!token.getUsername().equals(name)){
            //用户名不存在
            return null;  //shiro底层会抛出UnKnowAccountExceeption
        }
          //2 判断密码
        return new SimpleAuthenticationInfo("",password,"");
    }

整合mybatis

添加依赖

   <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.12</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

编写application.yml

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.108.128:3306/tensquare_user
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource    #druid数据源


mybatis:
  type-aliases-package: com.liwei.domain  #配置实体路径在mapper.xml中,返回实体可以不用写前置路径
  mapper-locations: mapperXml/*.xml

在启动类上加扫mapper(dao)注解

@SpringBootApplication
@MapperScan("com.liwei.shiro.mapper")
public class ShiroApplication {
    public static void main(String[] args) {
        SpringApplication.run(ShiroApplication.class);
    }
}

mapper

public interface UserMapper {

    User findByMobil(String mobile);
}

service

public interface UserService {
    User findByMobil(String mobile);
}

serviceimpl

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public User findByMobil(String mobile) {
        return userMapper.findByMobil(mobile);
    }
}

controller

    @PostMapping (value = "/login")
    public String login(String mobile,String password,Model model){
        /**
         * 使用Shiro编写认证操作
         */
        //1.获取SUbject
        Subject subject = SecurityUtils.getSubject();
        //2分装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(mobile,password);
        //3.执行登录方法
        try {
            subject.login(token);
            //登录成功
            return "redirect:getinfo";
        } catch (UnknownAccountException e) {
           // e.printStackTrace();
            //登录失败
            model.addAttribute("msg","用户名不存在");
            return "login";
        }catch (IncorrectCredentialsException e) {
            //e.printStackTrace();
            //登录失败
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }
}

在自定义Realm中编写登录验证

/**
 * 自定义Realm
 */
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    /**
     * 执行授权逻辑
     * @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("执行认证逻辑");
        //假设数据库的用户名和密码  模拟数据库
        //编写shiro判断逻辑,判断用户名和密码
        //1.判断用户名
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        User user = userService.findByMobil(token.getUsername());

        if(user==null){
            //用户名不存在
            return null;  //shiro底层会抛出UnKnowAccountExceeption
        }
          //2 判断密码
        return new SimpleAuthenticationInfo("",user.getPassword(),"");
    }
}

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

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

          TODO授权过滤器
               // 注意:当前授权拦截后,shiro会自动跳转到未授权页面
            filterMap.put("/user/add","perms[user:add]");  // user/add 拦截的路径名
            //设置未授权提示页面
               shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");  //自定义的提示页面路径  /noauth 路径请求地址
        shiroFilterFactoryBean.setLoginUrl("/tologin");   //自定义设置拦截跳转登录页面,默认是login.jsp
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;

    }

    /**
     * 创建DefaultWebSecurityManager
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        //@Qualifier("userRealm")将userRealm注入当前类
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    /**
     * 创建Realm
     */
    @Bean(name = "userRealm")
    public UserRealm getRealm(){
        return new UserRealm();
    }
}

实现数据库动态绑定

在数据库中添加一个权限字段
perms 数值设置为:user:add user:update user:delete

#### 增加依赖  实现thymeleaf动态标签

<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>

**
 * 自定义Realm
 */
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    /**
     * 执行授权逻辑
     * @param principalCollection
     * @return
     */
    @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.getPerms());     //设置授权字段号
        return info;
    }
    /**
     * 执行认证逻辑
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行认证逻辑");
        //假设数据库的用户名和密码  模拟数据库
        //编写shiro判断逻辑,判断用户名和密码
        //1.判断用户名
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        User user = userService.findByMobil(token.getUsername());
        if(user==null){
            //用户名不存在
            return null;  //shiro底层会抛出UnKnowAccountExceeption
        }
          //2 判断密码
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }
}

配置拦截器信息

@Configuration
public class ShiroConfig {
    /**
     * 创建ShiroFilterFactoryBean
     */
           @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            //设置安全管理器
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            //添加Shrio内置过滤器
            /**
             * Shiro内置过滤器,可以实现权限相关的拦截器
             *     常用的过滤器:
             *        anon:无需认证(登录)可以访问
             *        authc:必须认证才可以访问
             *        user:如果使用rememberMe的功能可以直接访问
             *        perms:该资源必须得到资源权限才可以访问
             *        role:该资源必须得到角色权限才可以访问
             */
            Map<String ,String> filterMap = new LinkedHashMap<>();
//        filterMap.put("/add","authc");
//        filterMap.put("/update","authc");
            filterMap.put("/login","anon");
            filterMap.put("/tologin","anon");
            filterMap.put("/getinfo","anon");
            filterMap.put("/*","authc");
            //对用户的修改功能进行授权
            filterMap.put("/user/update","perms[user:update]");
            //授权过滤器
               // 注意:当前授权拦截后,shiro会自动跳转到未授权页面
            filterMap.put("/user/add","perms[user:add]");
            //设置未授权提示页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
        shiroFilterFactoryBean.setLoginUrl("/tologin");   //自定义设置拦截跳转登录页面,默认是login.jsp
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;

    }

    /**
     * 创建DefaultWebSecurityManager
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        //@Qualifier("userRealm")将userRealm注入当前类
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    /**
     * 创建Realm
     */
    @Bean(name = "userRealm")
    public UserRealm getRealm(){
        return new UserRealm();
    }

    /**
     * 配置shiroDialect,用于thymeleaf和shiro标签配合使用
     */
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }
}

controller

    @Autowired
    private UserService userService;

    @GetMapping("/noauth")
    public String noauth(){
        return "/noauth";
    }

    @PostMapping (value = "/login")
    public String login(String mobile,String password,Model model){
        /**
         * 使用Shiro编写认证操作
         */
        //1.获取SUbject
        Subject subject = SecurityUtils.getSubject();
        //2分装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(mobile,password);
        //3.执行登录方法
        try {
            subject.login(token);
            //登录成功
            return "redirect:getinfo";
        } catch (UnknownAccountException e) {
           // e.printStackTrace();
            //登录失败
            model.addAttribute("msg","用户名不存在");
            return "login";
        }catch (IncorrectCredentialsException e) {
            //e.printStackTrace();
            //登录失败
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }
}

前端页面--结合动态标签实现隐藏连接,有增加的用户看不到修改的

<!DOCTYPE html>
<html xmlns:shiro="http://www.w3.org/1999/xhtml" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8"/>
    <title>测试页面</title>
</head>
<body>
用户测试页面
<div>
    <h3 th:text="${name}"></h3>
</div>
<hr/>
<div shiro:hasPermission="user:add">
进入用户添加功能: <a href="user/add">添加用户</a><br/>
</div>
<div shiro:hasPermission="user:update">
进入用户更新功能: <a href="user/update">更新用户</a><br/>
</div>
</body>
</html>
上一篇 下一篇

猜你喜欢

热点阅读