前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot集成Shiro框架

SpringBoot集成Shiro框架

作者头像
背雷管的小青年
发布2020-06-09 15:26:44
8390
发布2020-06-09 15:26:44
举报
文章被收录于专栏:技术开发——你我他

目标:实现Spring Boot集成shiro权限认证框架 工具:IDEA--2020.1 学习目标:实现Spring Boot集成shiro权限认证框架 本次学习的工程有点多,需要就请联系作者!

shiro相关配置

  • 构建一个springboot工程,添加shiro相关依赖:

代码语言:javascript
复制
    <!-- shiro依赖配置 -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.4.0</version>
    </dependency>
  • 如果有验证码获取其他的验证工具的话,我们可以编写自定义表单认证过滤器(在验证用户名和密码之前认证):

代码语言:javascript
复制
package com.xmaven.form;

import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class CustomFormAuthenticationFilter extends FormAuthenticationFilter {
    
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest req=(HttpServletRequest) request;
        String code1 = req.getParameter("randomcode");
        System.out.println("用户输入的验证码:"+code1);
        String code2 = (String) req.getSession().getAttribute("validateCode");
        System.out.println("系统生成的验证码是:"+code2);
        if(code1==null||code2==null) {
    req.setAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME,"randomCodeError");
            return true;
        }else {
            if(!code1.equals(code2)) {
                 
    req.setAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME,"randomCodeError");

                return true;
            }
        }
        return super.onAccessDenied(request, response);
    }
}
  • 编写一个自定义realm(自定义Realm的方法,从数据库中获取对应的记录返回给Shiro。实际上需要继承org.apache.shiro.realm.AuthenticatingRealm类,实现doGetAuthenticationInfo(AuthenticationToken paramAuthenticationToken)方法,授权需要实现这个方法: AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0)这个授权操作,最后由Shiro完成对密码的比对)
代码语言:javascript
复制
public class CustomRealmMD5 extends AuthorizingRealm {


    @Autowired
    SysUserService sysUserService;
    @Autowired
    SysPermissionService sysPermissionService;

    //用户授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {

        SysUser sysUser = (SysUser) arg0.getPrimaryPrincipal();
        System.out.println("当前被认证的用户是:"+sysUser.getUsername());
        //从数据库查询改用户拥有哪些权限
        List<String> list = new ArrayList<String>();
        List<SysPermission> perms = sysPermissionService.getPercodeByUsercode(sysUser.getUsercode());
        if (perms!=null&&perms.size()>0) {
            System.out.println("该用户拥有以下权限:");
            for (SysPermission perm : perms) {
                String code = perm.getPercode();
                if(code!=null&&!code.equals("")) {
                    System.out.println("========================="+code);
                    list.add(code);//把权限源添加到list集合
                }
            }
        }

        SimpleAuthorizationInfo  info = new SimpleAuthorizationInfo();
        info.addStringPermissions(list);
        return info;

    }
    //用户认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        String username = (String) token.getPrincipal();
        System.out.println("当前被认证的用户是:"+username);
        //1.需要从数据库查询是否有该用户
        SysUser sysUser = sysUserService.login(username);
        if(sysUser == null) {
            System.out.println("不存在此用户");
        }
        //2.该用户的密码
        String password = sysUser.getPassword();
        String salt = sysUser.getSalt();
        //第一个参数可以是任意类型object
        SimpleAuthenticationInfo info =new SimpleAuthenticationInfo(sysUser, password,ByteSource.Util.bytes(salt), super.getName());
        return info;
    }

}
  • 编写一个shiro配置类,关乎与,密码解析方式,安全管理器,shiro过滤器:

代码语言:javascript
复制
@Configuration  //配置类
public class ShiroConfig {

    @Autowired
    SysPermissionService sysPermissionService;

    //MD5方法解析密码
    @Bean
    public CustomRealmMD5 customRealmMD5() {
        CustomRealmMD5 realm = new CustomRealmMD5();
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");
        matcher.setHashIterations(3);
        realm.setCredentialsMatcher(matcher);
        return realm;
    }

    //安全管理器
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        //设置加密认证
        manager.setRealm(this.customRealmMD5());
        return manager;
    }

    //Shiro过滤器
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter() {
        //1.如果实现了验证码,该类名需要更换成自定义表单认证过滤器
        //FormAuthenticationFilter form = new FormAuthenticationFilter();
        //2.自定义表单认证过滤器(使用的是jsp验证码)
        //CustomFormAuthenticationFilter form = new CustomFormAuthenticationFilter();
        //3.使用的是kaptcha验证码生成器更加稳定
        CaptchaValidateFilter form = new CaptchaValidateFilter();
        form.setLoginUrl("/loginctrl/login.do");
        form.setUsernameParam("uname");
        form.setPasswordParam("upass");

        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(this.securityManager());
        shiroFilter.setLoginUrl("/login.jsp");
        shiroFilter.setSuccessUrl("/loginctrl/main.do");
        shiroFilter.setUnauthorizedUrl("/nopermission.jsp");


        LogoutFilter logout = new LogoutFilter();
        logout.setRedirectUrl("/login.jsp");

        Map<String, Filter> filters = new HashMap<String, Filter>();
        filters.put("authc", form);
        filters.put("logout", logout);
        shiroFilter.setFilters(filters);

        Map<String, String> map = new LinkedHashMap<String, String>();
        //anon:可匿名访问,authc:需要认证才能访问
        map.put("/css/**", "anon");
        map.put("/images/**", "anon");
        map.put("/js/**", "anon");
        map.put("/sql/**", "anon");
        map.put("/upload/**", "anon");
        map.put("/login.jsp", "anon");
        map.put("/login2.jsp", "anon");
        map.put("/main.jsp", "anon");
        map.put("/index.jsp", "anon");
        map.put("/captcha/**", "anon");
        //登出,退出登录
        map.put("/logout.do", "logout");
        map.put("/validatecode.jsp", "anon");
        //权限设置(从权限表查询所有的权限并且设置)
        List<SysPermission> list = sysPermissionService.getAllPermissions();
        if (list!=null&&list.size()>0) {
            System.out.println("所有权限并设置:");
            for (SysPermission perm : list) {
                String url = perm.getUrl();
                String code = perm.getPercode();
                if(code!=null&&!code.equals("")&&url!=null&&!url.equals("")) {
                    System.out.println("=====url======="+url+"========code====="+code);
                    map.put(url, "perms["+code+"]");
                }
            }
        }
        // user指的是用户认证通过或者配置了Remember Me记住用户登录状态后可访问
        map.put("/**", "authc");
        shiroFilter.setFilterChainDefinitionMap(map);
        return shiroFilter;
    }
}
  • 我们里面有登陆请求路径和成功的路径我们先来写一下这个登录的控制器:

代码语言:javascript
复制
//把该类注册成bean对象,并且作为控制器组件
@Controller
//给该类配置一个请求映射的url地址
@RequestMapping("/loginctrl")
public class LoginController {



    //登陆失败的方法
    @RequestMapping("/login.do")
    public ModelAndView login(ModelAndView mav,HttpServletRequest req) {
        System.out.println("用户认证失败");
        //通过认证失败的属性名称获取对应的值
        String msg = (String) req.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
        System.out.println("认证失败的消息:"+msg);
        String fail = "";
        if (msg!=null) {
            if (msg.equals(UnknownAccountException.class.getName())) {
                fail = "unknown";//账户不存在
            }else if (msg.equals(IncorrectCredentialsException.class.getName())) {
                fail = "error";
            }else if (msg.equals("randomCodeError")) {
                fail = "code";
            }else {
                fail = "other";
            }
        }
        mav.setViewName("redirect:../login.jsp?isfail="+fail);
        return mav;
    }
    @RequestMapping("/main.do")
    public ModelAndView main(ModelAndView mav,HttpSession session,String rememberMe) {
        System.out.println("用户认证成功");
        Subject subject = SecurityUtils.getSubject();
        SysUser sysUser = (SysUser) subject.getPrincipal();
        session.setAttribute("nowuser", sysUser);
        mav.setViewName("redirect:../main.jsp");
        return mav;
    }

}

本次工作包括知识过多,需要请联系作者,谢谢合作!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • shiro相关配置
相关产品与服务
验证码
腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档