springboot整合shiro实现登录认证以及授权

1.添加shiro的依赖

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

2.先创建一个Realm

public class MyShiroRealm extends AuthorizingRealm {
    @Autowired
    private RoleService roleService;//角色模模块
    @Autowired
    private UserService userService;//用户模块
    @Autowired
    private PermissionService permissionService;//权限模块
    /**
     * 用户身份识别(登录")
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken authToken = (UsernamePasswordToken) authenticationToken;
        // 获取用户输入的账号
        String userName = authToken.getUsername();     //通过账号查找用户信息
        User user= userService.selectUserOne(userName);// 将账户名,密码,盐值,getName()实例化到SimpleAuthenticationInfo中交给Shiro来管理
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                                                            user,
                                                            user.getPassWord(),                                    //这里是设置的密码盐
                                                            ByteSource.Util.bytes(user.getSalt()),
                                                            getName());
        return authenticationInfo;
    }

    /**
     * 访问控制。比如某个用户是否具有某个操作的使用权限
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        String userName  = (String) principalCollection.getPrimaryPrincipal();
        if (userName == null) {
            log.error("授权失败,用户信息为空!!!");
            return null;
        }
        try {
            //获取用户角色集
            Set<String> listRole= roleService.findRoleByUsername(userName);
            simpleAuthorizationInfo.addRoles(listRole);
            //通过角色获取权限集
            for (String role : listRole) {
                Set<String> permission= permissionService.findPermissionByRole(role);
                simpleAuthorizationInfo.addStringPermissions(permission);
            }
            return simpleAuthorizationInfo;
        } catch (Exception e) {
            log.error("授权失败,请检查系统内部错误!!!", e);
        }
        return simpleAuthorizationInfo;
    }
}

3.创建shiro的配置类

@Configuration
public class ShiroConfiguration {
   //配置自定义的Realm
    @Bean
    public MyShiroRealm myShiroRealm(HashedCredentialsMatcher matcher){
        MyShiroRealm myShiroRealm= new MyShiroRealm();
     //在这里配置密码加密
        myShiroRealm.setCredentialsMatcher(matcher);
        return myShiroRealm;
    }
   //将Realm注册到securityManager中
    @Bean
    public DefaultWebSecurityManager securityManager(HashedCredentialsMatcher matcher){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm(matcher));
        return securityManager;
    }

    //如果没有此name,将会找不到shiroFilter的Bean
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(org.apache.shiro.mgt.SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/login");         //表示指定登录页面
        shiroFilterFactoryBean.setSuccessUrl("/user/list");   // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");    //未授权页面

        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();//拦截器, 配置不会被拦截的链接 顺序判断
        filterChainDefinitionMap.put("/login","anon");                     //所有匿名用户均可访问到Controller层的该方法下
        filterChainDefinitionMap.put("/userLogin","anon");
        filterChainDefinitionMap.put("/image/**","anon");
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/fonts/**","anon");
        filterChainDefinitionMap.put("/js/**","anon");
        filterChainDefinitionMap.put("/logout","logout");
        filterChainDefinitionMap.put("/**", "authc");  //authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
        //filterChainDefinitionMap.put("/**", "user");        //user表示配置记住我或认证通过可以访问的地址
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * SpringShiroFilter首先注册到spring容器
     * 然后被包装成FilterRegistrationBean
     * 最后通过FilterRegistrationBean注册到servlet容器
     * @return
     */
    @Bean
    public FilterRegistrationBean delegatingFilterProxy(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName("shiroFilter");
        filterRegistrationBean.setFilter(proxy);
        return filterRegistrationBean;
    }
    //设置cookie
    @Bean
    public SimpleCookie rememberMeCookie(){
        //这个参数是cookie的名称,对应前端的checkbox的name=rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //记住我cookie生效时间3个小时(单位秒)
        simpleCookie.setMaxAge(10800);
        return simpleCookie;
    }
    //cookie管理对象,记住我功能
    @Bean
    public CookieRememberMeManager rememberMeManager(){
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        return cookieRememberMeManager;
    }
    /**
     * 密码匹配凭证管理器(密码加密需要此配置)
     * @return
     */
    @Bean(name = "hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        hashedCredentialsMatcher.setHashIterations(1024);// 设置加密次数
        return hashedCredentialsMatcher;
    }
    //如果没有这两个配置,可能会授权失败,所以依赖中还需要配置aop的依赖
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(HashedCredentialsMatcher matcher) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager(matcher));
        return authorizationAttributeSourceAdvisor;
    }
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
}

4.新建controller并写个登录的方法

/**
     * 登录页面 这里对应shiro中配置的shiroFilter的登录方法
     * @return
     */
    @GetMapping("/login")
    public String login() {
        return "user/login";
    }
//登录方法    @PostMapping("/userLogin")
    public String toLogin( String userName,String passWord,Model model){
        UsernamePasswordToken token =new UsernamePasswordToken(userName,passWord);
        Subject subject = SecurityUtils.getSubject();
        try {            //这里直接使用shiro的登录方法
            subject.login(token);
            return "redirect:user/list";         //登录失败时,会catch到你的异常,异常通过全局处理
        } catch (UnknownAccountException e) {
            model.addAttribute("msg","该账号不存在");              
        } catch (IncorrectCredentialsException e) {
            model.addAttribute("msg","密码错误,请重试");          
        } catch (LockedAccountException e) {
            model.addAttribute("msg","该账户已被锁定,请联系管理员");
        } catch (Exception e) {
            model.addAttribute("msg","登录失败");
        }
        return "user/login";
    }//添加
@RequestMapping("/insertUser")@ResponseBodypublic int insertUser(User user){    //将uuid设置为密码盐值    String salt = UUID.randomUUID().toString().replaceAll("-","");    SimpleHash simpleHash = new SimpleHash("MD5", user.getPassWord(), salt, 1024);   //添加用户信息    user.setPassWord(simpleHash.toHex()).setValid(1).setSalt(salt).setCreateTime(new Date()).setDel(0);    return  userMapper.insertSelective(user);}
 

5.创建全局异常处理类

@RestControllerAdvice
public class GlobalExceptionHandle {
    @ExceptionHandler(ShiroException.class)
    public String doHandleShiroException(ShiroException se,Model model) {
        se.printStackTrace();
    if(se instanceof UnknownAccountException) return "账户不存在!";    else if(se instanceof LockedAccountException) return "账户已锁定,请联系管理员";    else if(se instanceof IncorrectCredentialsException) return "密码错误,请重试";    else if(se instanceof AuthorizationException) return "没有相应权限,请联系管理员";    else return "登录失败";
  }}

权限需要开启权限注解才生效

@GetMapping("/userPageList")  
    @ResponseBody
    @RequiresPermissions("user:view") //这里是用户对应的权限
    public PageList listPage(HttpServletRequest request){
        PageList pageList = new PageList();
        List<User> list= userService.findAllPage(request);//查询出的条数
        int totalCount = userService.countAll();//总记录数
        pageList.setRows(list);
        pageList.setTotal(totalCount);
        return pageList;
    }

shiro用户角色和权限表

-- Table structure for `sys_permission`
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
  `id` int(64) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  `permission` varchar(32) DEFAULT NULL,
  `url` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES (‘1‘, ‘用户管理‘, ‘user:view‘, ‘user/userPageList‘);
INSERT INTO `sys_permission` VALUES (‘2‘, ‘用户添加‘, ‘user:add‘, ‘user/saveUser‘);
INSERT INTO `sys_permission` VALUES (‘3‘, ‘用户删除‘, ‘user:del‘, ‘user/delById‘);

-- ----------------------------
-- Table structure for `sys_role`
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
  `id` int(64) NOT NULL,
  `available` varchar(8) DEFAULT NULL,
  `description` varchar(32) DEFAULT NULL,
  `role` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (‘1‘, ‘1‘, ‘管理员‘, ‘admin‘);
INSERT INTO `sys_role` VALUES (‘2‘, ‘1‘, ‘VIP会员‘, ‘vip‘);

-- ----------------------------
-- Table structure for `sys_role_permission`
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
  `permission_id` int(64) NOT NULL COMMENT ‘权限表主键‘,
  `role_id` int(64) NOT NULL COMMENT ‘角色表主键‘
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_role_permission
-- ----------------------------
INSERT INTO `sys_role_permission` VALUES (‘1‘, ‘1‘);
INSERT INTO `sys_role_permission` VALUES (‘2‘, ‘1‘);

-- ----------------------------
-- Table structure for `sys_user_role`
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
  `role_id` int(64) NOT NULL,
  `user_id` int(64) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (‘1‘, ‘1‘);

-- ----------------------------
-- Table structure for `user_info`
-- ----------------------------
DROP TABLE IF EXISTS `user_info`;
CREATE TABLE `user_info` (
  `id` int(64) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL,
  `salt` varchar(64) DEFAULT NULL,
  `state` varchar(8) DEFAULT NULL,
  `username` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user_info
-- ----------------------------
INSERT INTO `user_info` VALUES (‘1‘, ‘管理员‘, ‘d3c59d25033dbf980d29554025c23a75‘, ‘8d78869f470951332959580424d4bf4f‘, ‘1‘, ‘admin‘);

最后声明下!!!我的开发环境是windows10+JDK1.8+springboot2.1.7+shiro1.4.0

相关推荐