spring整合shiro系列(二)SSM整合shiro

前言

在之前我们已经对于Shiro这个安全管理框架有了一定的认识,同时也已经在SSM框架环境下对于Shiro进行了配置,下面我们来看看如何具体使用Shiro进行开发。

SSM框架

这里简单的说一下,因为这里使用的是Spring+Spring MVC+Mybatis框架,我是之前就搭好的。可能有些同学喜欢用Spring Boot来整合,这也是没有问题的,后面有空会把Spring Boot的整合放上来。回到SSM框架上,这个应该算是java中比较经典的一个框架组合,会的同学不用说自己可以搭建,如果有不太清楚SSM的后面准备再写一篇SSM框架的,大家一起学习一下。

下面是我项目的总体结构

还是中规中矩的Web层-Serivce层-Dao层,spring配置文件我根据不同的功能分开放置这样更加清晰。

然后是Shiro的两个文件,一个是自定义的Realm,用于验证用户和授予权限的;另一个是进行加密的。

开发中先写一个注册的功能用于添加用户,简单一点的话就是需要用户名,密码(密码这里用MD5+盐)。这两点是基本的。

下面是代码的一个片段,这里我是通过UUID生成了一个盐对原密码加密,然后就用到我们之前的加密用的文件

User user = new User();
        String salt = UUIDUtil.createUUID().toString();
        Date createTime = new Date();
        Integer state = 0;
        user.setUserName(userName);
        user.setPassword(password);
        user.setSalt(salt);
        user.setCreateTime(createTime);
        user.setState(state);
        User newUser = passWordHelper.encryptPassword(user);
@Component
public class PassWordHelper {

    private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();

    @Value("MD5")
    private String algorithmName;
    @Value("2")
    private int hashIterations;

    public void setRandomNumberGenerator(RandomNumberGenerator randomNumberGenerator) {
        this.randomNumberGenerator = randomNumberGenerator;
    }

    public void setAlgorithmName(String algorithmName) {
        this.algorithmName = algorithmName;
    }

    public void setHashIterations(int hashIterations) {
        this.hashIterations = hashIterations;
    }

    public User encryptPassword(User user){
        if(user.getSalt() == null || "".equals(user.getSalt())){
            user.setSalt(randomNumberGenerator.nextBytes().toHex());
        }
        String newPassword = new SimpleHash(algorithmName,user.getPassword(),
                ByteSource.Util.bytes(user.getSalt()),hashIterations).toHex();
        user.setPassword(newPassword);
        return user;
    }

}

这里引用了加密方式和加密次数两个参数,然后通过SimpleHash进行加密,得到一个加密后的密码放入user对象中,然后在Serivce层中将新的user传入Dao层添加到数据库。ok,现在我们已经有一个用户了,你也可以用别的方法,只要保证先添加一个用户进来就对了。

下面来看一下Realm文件

 

public class myRealm extends AuthorizingRealm{

    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionService permissionService;

    /**
     * @description 为当前登录的用户授予角色和权限
     * @author zhou
     * @created  2018/10/17 15:15
     * @param
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取用户名
        String userName = (String)principalCollection.getPrimaryPrincipal();
        Session session = SecurityUtils.getSubject().getSession();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //查询用户的role
        Set<String> roles = roleService.findRoleByUserName(userName);
        authorizationInfo.setRoles(roles);

        //查询用户的permission
        Set<String> permissions = permissionService.findPermissionByUserName(userName);
        authorizationInfo.setStringPermissions(permissions);
        return authorizationInfo;
    }

    /**
     * @description 验证当前登录的用户
     * @author zhou
     * @created  2018/10/17 15:16
     * @param
     * @return
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws
            AuthenticationException {
        //获得用户信息
        String userName = (String)authenticationToken.getPrincipal();
        //从数据库中查找
        User user = userService.findByUserName(userName);
        if(user==null){
            //账号不存在
            throw new UnknownAccountException();
        }else if(user.getState() == 1){
            //账号锁定
            throw new LockedAccountException();
        }
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user.getUserName(),
                user.getPassword(), ByteSource.Util.bytes(user.getSalt()),getName());
        return simpleAuthenticationInfo;
    }
}

首先新建一个自定义的Realm,然后继承AuthorizingRealm,重写其中的doGetAuthorizationInfo和doGetAuthenticationInfo两个方法。

首先看一下授权的方法,这里是通过用户名去我们的数据库中查询该用户的角色和权限,这里用set集合去存放角色和权限。然后把这两个信息存到authorizationInfo中,这样在用户被授权后,如果用户要执行什么操作,可以从中获取数据来判断用户是否具有对应的权限。

然后是登录验证的方法,这个和平时写的javaWeb的验证方式比较类似,首先获得用户名去数据库中查找用户信息,然后做一些简单的校验比如是否存在用户和用户是否被锁定等等。然后将用户名,密码,盐和Realm的名称。然后在登录的时候会用到这些。下面是我的登录代码

 @RequestMapping(value = "/login")
    public WebResponse userLogin(@RequestParam("userName") String userName,@RequestParam("password") String password,
                                 @RequestParam(value = "rememberMe",defaultValue = "false") boolean rememberMe,
                                         HttpServletRequest request){
        if(isEmpty(userName)||isEmpty(password)){
            log.error("用户名或密码为空");
            return new WebResponse().error(401,null,"用户名或密码为空");
        }
        //查询角色
        Set<String> roleList = roleService.findRoleByUserName(userName);
        //查询权限
        Set<String> permissionList = permissionService.findPermissionByUserName(userName);
        //获得主体
        Subject currentUser = SecurityUtils.getSubject();
        //判断用户是否登陆
        if(!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
            try {
                //token.setRememberMe(rememberMe);
                //存入参数
                request.getSession().setAttribute("token",userName);
                request.getSession().setAttribute("role",roleList);
                request.getSession().setAttribute("permission",permissionList);
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                log.error("账号不存在");
                return new WebResponse().error(402, null, "账号不存在");
            } catch (IncorrectCredentialsException ice) {
                log.error("密码错误,请重试");
                return new WebResponse().error(403, null, "密码错误,请重试");
            } catch (LockedAccountException lae) {
                log.error("该账号已被禁用,无法登陆");
                return new WebResponse().error(404, null, "该账号已被禁用,无法登陆");
            } catch (AuthenticationException ae) {
                log.error("未知错误");
                return new WebResponse().error(405, null, "未知错误");
            }
        }
        HashMap<String,Object> userMap = new HashMap<>();
        userMap.put("msg",userName + "登陆成功");
        userMap.put("role",roleList);
        userMap.put("permission",permissionList);
        return new WebResponse().ok(userMap);
    }

这里主要看这个login()方法,当程序判定该用户未被认证时,将用户名和密码放入Token中然后调用login,此时就会用到之前realm中用户验证的方法,将用户输入的信息和数据库中查到的信息进行比对校验。

后面是一些捕获异常比如账号不存在,密码错误,账号锁定等等。

以上就是Shiro权限登录的一个流程和整合过程中所需要的文件。

不过就个人觉得由于Shiro框架封装程度比较高,感觉看似随意调用了几个方法就实现了验证和授权,其实底层做的工作和javaWeb中做的是类似的。后面有机会会从源码的角度再次剖析一下Shiro的Realm的工作原理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值