shrio&springboot&layui 前后端分离思路,及实现核心业务逻辑

总结:上期我们说到表设计,这次来实现。

            前后端分离思路:登入返回 token 根据token 获取菜单数据,动态渲染 路由。重新shiro 的处理逻辑就行,如没有权限,未认证 登 返货json 格式。(前端控制 路由跳转,后端负责数据)

            不分离 就常规套路,登入后 获取菜单信息 渲染页面,未认证直接跳转 登入页,或者没有权限页面,也可以通过标签 直接看不到,反正就是简单的很。(后端负责所有页面跳转和数据扭转)。

           核心代码如下:

          

public class CustomRealm extends AuthorizingRealm {

    @Autowired
    private SysUsersService sysUsersService;

    @Autowired
    private SysUsersMapper usersMapper;


    /**
     * 授权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            throw new AuthorizationException("请重新登入");
        }
        // principals 就是 认证 传的 第一个 参数 传什么 强转什么
        SysUsers user = (SysUsers) getAvailablePrincipal(principals);

        List<SysPermissions> list = usersMapper.getPermissions(user.getId());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Set<String> permissions = list.stream().map(e->e.getPermission()).collect(Collectors.toSet());
        info.setStringPermissions(permissions);
        return info;
    }

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

        UsernamePasswordToken fromToken = (UsernamePasswordToken) token;
        String username = fromToken.getUsername();

        QueryWrapper<SysUsers> queryWrapper = new QueryWrapper();
        List<SysUsers> usersList = sysUsersService.list(queryWrapper);
        if(CollectionUtils.isEmpty(usersList)){
            throw new UnknownAccountException("用户不存在");
        }
        SysUsers user = usersList.get(0);
        // 一般重次 登入 3次 密码错误 就锁定 需要重下 shiro 登入失败 逻辑
        if(user.getLocked()>0){
            throw new LockedAccountException("账户被锁定,请联系管理员");
        }
        //从数据 查询 根据用户username 用户 然后 交给 shiro 去匹配 密码 用户名 相等
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
       /* if (user.getSalt() != null) {
            info.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
        }*/

        return info;

    }

}

  核心配置如下:

      

@Configuration
public class ShiroConfig {

    /**
     *  注入自定义的realm,告诉shiro如何获取用户信息来做登录或权限控制
     */

    @Bean
    public Realm realm() {
        return new CustomRealm();
    }


    /**
     * 这里统一做鉴权,即判断哪些请求路径需要用户登录,哪些请求路径不需要用户登录。
     * 这里只做鉴权,不做权限控制,因为权限用注解来做。
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        Map<String, String> chainDefinition = new LinkedHashMap<>();
        chainDefinition.put("/user/index", "anon");
        chainDefinition.put("/user/login", "anon");
        chainDefinition.put("/static/**", "anon");
        chainDefinition.put("/css/**", "anon");
        chainDefinition.put("/js/**", "anon");
        chainDefinition.put("/swagger-ui.html", "anon");
        chainDefinition.put("/doc.html", "anon");
        chainDefinition.put("/swagger-resources", "anon");
        chainDefinition.put("/swagger-resources/configuration/security", "anon");
        chainDefinition.put("/swagger-resources/configuration/ui", "anon");
        chainDefinition.put("/v2/api-docs", "anon");
        chainDefinition.put("/webjars/springfox-swagger-ui/**", "anon");



        // 1、创建过滤器Map,用来装自定义过滤器
        LinkedHashMap<String, Filter> map = new LinkedHashMap<>();
        // 2、将自定义过滤器放入map中,如果实现了自定义授权过滤器,那就必须在这里注册,否则Shiro不会使用自定义的授权过滤器
        map.put("authc", new MyFormAuthenticationFilter());
        // 3、将过滤器Ma绑定到shiroFilterFactoryBean上
        factoryBean.setFilters(map);

        //设置 未认证跳转 当然重写 过滤器 也可以
        factoryBean.setLoginUrl("/user/unauth");
        //设置 未授权跳转
        factoryBean.setUnauthorizedUrl("/user/unperms");

        //除了以上的请求外,其它请求都需要登录
        chainDefinition.put("/**", "authc");
       // chainDefinition.put("/**", "anon");
        factoryBean.setFilterChainDefinitionMap(chainDefinition);
        return factoryBean;
    }

    @Bean
    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        /**
         * setUsePrefix(false)用于解决一个奇怪的bug。在引入spring aop的情况下。
         * 在@Controller注解的类的方法中加入@RequiresRole注解,会导致该方法无法映射请求,导致返回404。
         * 加入这项配置能解决这个bug
         */
        creator.setProxyTargetClass(true);
        creator.setUsePrefix(true);
        return creator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor
                = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }


    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        //securityManager.setRealms(Arrays.asList(realm()));
        securityManager.setRealm(realm());
        // securityManager.setCacheManager(cacheManager());
        // 设置realm. 可以设置 多ream 和 策略
        //securityManager.setAuthenticator(authenticator());
        return securityManager;
    }

     /*  //添加realm
    @Bean
    public Authenticator authenticator() {
        ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
        //设置两个Realm,一个用于用户登录验证和访问权限获取;一个用于jwt token的认证
        authenticator.setRealms(Arrays.asList(jwtRealm()));
        //设置多个realm认证策略,一个成功即跳过其它的
        authenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
        return authenticator;
    }*/
    /**
     * 使用默认session
     *
     * @return
     */
    @Bean(name="sessionManager")
    public ServletContainerSessionManager servletContainerSessionManager() {
        ServletContainerSessionManager sessionManager = new ServletContainerSessionManager();
        return sessionManager;
    }

  /*  *//**
     *  凭证匹配器
     * @return
     *//*
    @Bean(name = "hashedCredentialsMatcher")
    public HashedCredentialsMatcher getHashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher =  new HashedCredentialsMatcher("SHA-256");
        hashedCredentialsMatcher.setHashIterations(2);
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return hashedCredentialsMatcher;
    }*/

}

  效果如下:

 

 接口文档如下:

 

 

就是折磨简单 虽然没啥难度,但是今天还是搞了半天。

代码结构:

源码地址 有兴趣的可以看看

https://github.com/lyc88/shiro

posted @ 2019-12-28 19:52  川流不息&  阅读(2080)  评论(0编辑  收藏  举报