Shiro初学踩雷心得

setSuccessurl基本无效

这个方法是设置认证成功之后的跳转到的页面,但是试了很多方法都不能跳转。
解决办法是可以在方法返回时重定向到要跳转的页面,但是问题又来了。现在大多都喜欢在请求成功之后给前端一个json格式的返回值,里面带上状态码呀,字符串呀什么的,这样就不方便重定向来跳转页面。
可是如果前端页面只用form表单来往后台传值,后台对应的方法在处理完数据之后会自动跳转到该方法的接口页面

form表单请求成功之后跳转到action请求的路径的页面

举个例子:
前端:

<form action="/login" method="get">
    用户名:<input type="text" name="username" id="username">
    <br>
    密码:<input type="text" name="password" id="password">
    <br>
    <input type="submit" value="登陆" >
</form>

后台:

    @GetMapping("/login")
    @ResponseBody
    public Map<String,Object> login(String username,String password){
        System.out.println(username+"++++++++"+password);
        Map<String,Object> map = new HashMap<>();
        // 进行身份验证
        try {
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(username,password);
            // 登陆操作
            subject.login(token);
        }catch (IncorrectCredentialsException e){
            map.put("code",500);
            map.put("msg","用户不存在或密码错误");
            return map;
        }catch (LockedAccountException e){
            map.put("code",500);
            map.put("msg","登陆失败,用户已被冻结");
            return map;
        }catch (AuthenticationException e){
            map.put("code",500);
            map.put("msg","该用户不存在");
            return map;
        }catch (Exception e){
            map.put("code",500);
            map.put("msg","未知异常");
            return map;
        }
        map.put("code",200);
        map.put("msg","登陆成功");
        return map;
    }

ShiroConfig中设置successurl

 /**
     * shiro的基本配置
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager){
        // shiro的过滤器
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // securityManager是shiro的控制器,协调其他组件完成认证授权
        // 这里为过滤器添加控制器
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 申明过滤器配置的集合
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        // 配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
        shiroFilterFactoryBean.setLoginUrl("/toLogin");
        // 登录成功的页面
        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 登录失败的页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");

        // 注意过滤器配置顺序不能颠倒
        // 可直接访问的资源
        // 这里/login是处理登陆的method
        filterChainDefinitionMap.put("/login", "anon");
        // 静态资源(前后端分离的项目不需要配置这个)
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        // 未授权禁止访问的资源
        filterChainDefinitionMap.put("/**", "authc");
        // 对过滤器赋值
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

页面输入账号密码后自动跳转为
在这里插入图片描述
这样的一个页面。
从上面ShiroConfig中可以看到,successurl是设置了的,但是跳转的确是 /login的接口的json数据页面。就很离谱。

ajax需要请求两次,认证控制器才能起作用

好!!!
那我给它用ajax来往后台传值,因为前端可以控制页面的跳转(当然是在认证通过之后)
代码如下:
前端:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陆页面</title>
</head>
<body>
<form action="" method="get">
    用户名:<input type="text" name="username" id="username">
    <br>
    密码:<input type="text" name="password" id="password">
    <br>
    <input type="submit" value="登陆" onclick="login()">
</form>

</body>
<script src="/js/jquery.js"></script>
<script>
    function login()
    {
        var username = document.getElementById("username").value;
        var password = document.getElementById("password").value;
        $.ajax({
            type: 'get',
            url: "login",
            data: {
                "username": username,
                "password": password
            },
            success: function (data) {
                console.log(data)
                if (data.code == 200){
                    alert("登录成功!")
                    window.location.href="index";
                }else {
                    alert("登陆失败!用户名或密码错误")
                }
            }
        });
    }
</script>
</html>

这里把form表单中的 acthon不设置接口名,防止form和ajax都传值。
后台把ShiroConfig中的setSuccessurl给注释掉,其他不变。
js中的**window.location.href=“index”;**就可以控制页面的跳转了。
这样看着没问题
可是邪门的问题又来了(也许是我刚入门技术尚浅找不到问题所在)

这是最开始的登陆页面:
在这里插入图片描述
输入账号密码后点击登陆
前端页面变成这个样子
在这里插入图片描述
然后后台控制台输出为:
在这里插入图片描述
可以看到后台是拿到数据了的,最下面的那个对象地址是在ShiroRealm中认证方法中的输出,不多说看代码:

 /**
     * 身份认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 获取用户输入的账号
        String username = (String) authenticationToken.getPrincipal();
        System.out.println(username);
        // 通过username从数据库中查找 User对象,如果找到则进行验证
        TUser user = userService.selectUserByName(username);
//        System.out.println(user);
        // 判断账号是否存在
        if (user == null){
            throw new AuthenticationException();
        }
        // 判断账号是否被冻结
        if (user.getState() ==null || user.getState().equals("PROHIBIT")){
            throw new LockedAccountException();
        }
        // 进行验证
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                // 用户名
                user,
                // 密码
                user.getPassword(),
                // 盐值
//                ByteSource.Util.bytes(user.getSalt()),
                getName()
        );
        System.out.println(user);
        return authenticationInfo;
    }

可以看到认证管理器是拿到数据了的,但是没起作用。

这里说明一下:为什么说认证管理器没起作用呢,因为我试过在地址栏输localhost:8080/index,自动给我跳到登陆页面,说明没认证。

行!!!我不关服务器再请求一次
在这里插入图片描述
点击登陆之后:
在这里插入图片描述
跳转成功,同时认证也成功。
服务器的控制台打印数据:
在这里插入图片描述
这个问题就特别离谱。

form表单和ajax结合起来用

然后我把form表单和ajax结合起来用,虽然看着特别别扭,既form表单请求了后台,ajax也请求后台,看起来多次一举,但是就离谱的解决了这个问题。
前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陆页面</title>
</head>
<body>
<form action="/login" method="get">
    用户名:<input type="text" name="username" id="username">
    <br>
    密码:<input type="text" name="password" id="password">
    <br>
    <input type="submit" value="登陆" onclick="login()">
</form>

</body>
<script src="/js/jquery.js"></script>
<script>
    function login()
    {
        var username = document.getElementById("username").value;
        var password = document.getElementById("password").value;
        $.ajax({
            type: 'get',
            url: "login",
            data: {
                "username": username,
                "password": password
            },
            success: function (data) {
                console.log(data)
                if (data.code == 200){
                    alert("登录成功!")
                    window.location.href="index";
                }else {
                    alert("登陆失败!用户名或密码错误")
                }
            }
        });
    }
</script>
</html>

虽然很不规范,但是问题解决了。

单纯用ajax的话,前端拿不到后台传过来的数据

在后面写注册功能的时候我发现,只用ajax是拿不到后台传过来的json数据的,还是用ajax+form表单,才能解决这个问题!

认证成功,但是授权器没有运行

我用的注解的方式进行授权

这里主要是需要在ShiroConfig中开启Shiro的注解支持

  • 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
  • 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能

代码如下:

    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * 开启aop注解支持
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值