shiro笔记(四)

无意间找到了不通过ini配置认证策略的方式,赶紧记录一下:

DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
securityManager.setAuthenticator(authenticator);

 之前尝试的用户认证都是明文密码的,为了更接近于真实项目,决定参考教程的下一章节将密码设为加密数据,在这一章节中,首先介绍了一些shiro密码模块的方法的使用,本着初次使用力求简化的原则,我选择了MD5加密,salt

就使用用户账号,后续又介绍了DefaultPasswordService和PasswordMatcher以及缓存等,感觉示例代码还是给的少...看得有点云里雾里的,算了,还是沿用之前一贯的作风,看不懂的自己发挥,如果想实现密码重试次数限制的话,

我的想法是可以使用redis来存储这部分数据,实际上用户、角色、权限也都可以存入redis,但是为了简化代码快速实践,先忽略缓存这一回事,对于密码重试次数暂时不加限制。

代码实际上与前几篇笔记没什么太大区别,在注册时会使用shiro的加密方法将密码采用MD5的方式进行加密,然后再存入数据库。

new Md5Hash(password, salt, num).toString();

三个参数从左到右依次是密码、盐值、散列次数。

主要的问题在于现在数据库中的密码并非以明文存储,所以在认证时,也不能直接用明文密码与之相比较。

本来想参照网上一篇文章,自定义一个密码校验的方法,可能是哪里搞错了,最终并没有起作用。然后,我决定按照自己的方式来做:

SecurityUtils.getSubject().login(new UsernamePasswordToken(user.getAccount(),
                PasswordUtils.MD5(user.getPassword(), user.getAccount(), 2)));
PasswordUtils是我自己封装的工具类,方法内部实际上就是上面那一行MD5加密代码,登入时要构建用户名与密码组成的token,在此之前先将密码按照注册时的方式加密,然后再构建token传参。
底层的代码应该会拿着这个token和自定义realm中认证方法返回的token进行校验(个人猜测,没读过源码),经实践证明这种方式可行。
SecurityUtils.getSubject().isAuthenticated();

这一行代码能够判断用户是否认证成功,true为成功,false为失败。

然后,顺带着练一下授权,目前数据的来源依然是数据库,采用的是连表查询的方式获取角色和权限信息。

忘记mybatis相关的语法了,现查了一篇文章复习了一下一对多的注解语法,写的时候还是不慎将全限定类名搞错了...

由于这一次实践练习采用的是细粒度的模式,数据库中建了三张简易的表,用户表、角色表、权限表,其中关联数据为用户的账号。

@Select("select * from users where account = #{account}")
    @Results(id = "userAccountMap",value = {
            @Result(id =true,property = "id",column = "id"),
            @Result(property = "username",column = "username"),
            @Result(property = "account",column = "account"),
            @Result(property = "password",column = "password"),
            @Result(property = "roles",column = "account",many = @Many(select="com.blog.safe.modules.authc.mapper.AuthcMapper.getRoles",fetchType = FetchType.LAZY)),
            @Result(property = "permissions" ,column = "account",many = @Many(select="com.blog.safe.modules.authc.mapper.AuthcMapper.getPerm",fetchType = FetchType.LAZY))
    })
    User getUser(String account);

    @Select("select role from roles where account = #{account}")
    Set<String> getRoles(String account);

    @Select("select perm from permissions where account = #{account}")
    Set<String> getPerm(String account);

自定义的授权方法将数据取出后,封装为SimpleAuthorizationInfo对象返回。

  //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String account = (String) principalCollection.getPrimaryPrincipal();
        User user = authcMapper.getUser(account);
        System.out.println(user);
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        for (String s : user.getRoles()) {
            simpleAuthorizationInfo.addRole(s);
        }

        for (String s : user.getPermissions()) {
            simpleAuthorizationInfo.addStringPermission(s);
        }

        return simpleAuthorizationInfo;
    }

权限以注解的形式进行约束

@PostMapping("/submit")
@RequiresUser //必须先登录
@RequiresPermissions("article:submit") //必须拥有这个权限
public Data<Object, Object> submit(@RequestParam("article") String article)

传过来的参数可以是<p>... ...</p>这种格式直接存入数据库,保证数据的格式不会丢失

posted @ 2020-10-30 16:27  无心大魔王  阅读(175)  评论(0编辑  收藏  举报