shiro登录过程

工作流程:

浏览器将用户名、密码、是否记住登录等信息发送给登录controller ,

new UsernamePasswordToken()获取token,将用户名、加密后的密码、rememberMe,set到token中。SecurityUtils.getSubject();获取subject对象,执行subect.login(token)进行登录操作并捕获可能出现的账号密码错误等异常。

 

1.前端登录页面将用户名、密码、是否记住登录,传入到Controller

Controller登录方法:

//1.获取shiro中的subject对象
Subject subject = SecurityUtils.getSubject();
//2.对用户从页面输入的密码进行加密处理
password = new Md5Hash(password,username,1024).toString();
System.out.println("加密后的密码: " + password);
//3.创建shiro中的用户名和密码对象,将用户输入的用户名密码交给shiro管理
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//4.关于记住我的设置
System.out.println("是否记住我: " + rememberMe);
if(rememberMe){
    token.setRememberMe(true);
}
//5.调用shiro的登录方法,调用后,shiro会自动执行Realm实现类===========
try {
    subject.login(token);
    System.out.println("开始登陆");
} catch (UnknownAccountException e) {
    return new Result(1, "账号不存在");
}catch (IncorrectCredentialsException e){
    return new Result(1,"密码错误");
}catch (AuthenticationException e){
    System.out.println("其他异常");
    return new Result(1,"其他异常");
}
return new Result(0, "登陆成功!");

/**
 * 注销方法
 * @return
 */
public Result logout(){
    //1.获取subject对象
    Subject subject =  SecurityUtils.getSubject();
    //2.返回注销方法
    subject.logout();
    //3.返回
    return Result.ok("注销成功");
}

获取完数据后,shiro会自动执行Realm的实现类,实现类需要手动实现,如下:

/**
 * projectName: myproject
 * @author: xxx
 * time: 2021/9/6 21:17
 * description:  自定义realm对象
 *
 *  1.从数据库根据用户名,取出数据库中的用户名,密码交给shiro框架
 *  2.根据用户名,到数据库取出用户对应的角色和权限对象交给shiro框架管理
 */

public class MyUserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;
    @Autowired
    private MenuService menuService;
    @Autowired
    private RoleService roleService;

    /**
     *     用户输入的用户名和密码输入正确,校验完成后进行赋值操作
     *     根据用户名到数据库查询这个用户对应的角色和权限,交给shiro管理
     *     调用时机:在需要访问资源的时候,需要角色和权限的视乎才会调用此方法
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        System.out.println("已登陆成功,授予登录用户权限,也就是赋予用户对应的角色和能够访问的菜单");

        //1.获取当前登录的用户对象
        SysUsers sysUSers = (SysUsers) principalCollection.getPrimaryPrincipal();

        //2.获取当前登录用户的 用户id
        int uid = sysUSers.getId();

        //3.根据用户id,查询数据库中这个用户对应的角色集合和权限集合
        Set<String> roleList = roleService.findRoleListByUid(uid);
        Set<String> menuList = menuService.findMenuListbyUid(uid);

        //4.创建shiro中的用户权限对象
        SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();

        //5.将查询到的角色集合放入shiro的权限对象
        auth.setRoles(roleList);

        //6.将查询到的权限集合放入shiro的权限对象
        auth.setStringPermissions(menuList);

        //7.返回shiro权限对象
        return auth;
    }

    /**
     *     根据用户在页面输入的用户名,查询数据库中的用户名和密码,交给shiro框架
     *     让shiro框架进行对比用户名,密码是否正确
     *    调用时机:在controller调用subject.login(token);方法就会执行这个方法,进行用户名 密码校验
     * @param auth
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
        System.out.println("开始校验用户名和密码................");

        //1.获取用户在浏览器输入的用户名
        String userName = (String) auth.getPrincipal();
        //2.根据用户输入的用户名,查询数据库的用户对象
        String password = new String((char[]) auth.getCredentials());
        //3.判断用户是否为空,为空则抛出异常
        SysUsers sysUSer = userService.findUserbyName(userName);
        if (sysUSer == null) {
            throw new UnknownAccountException("账号不存在,请先注册,再登录!");
        }
        //4.对比数据库的密码和用户输入的密码是否一致
        if(!password.equals(sysUSer.getPassword())){
            throw new IncorrectCredentialsException("密码错误");
        }
        //5.判断用户状态,1正常,其他为锁定状态
        if(sysUSer.getStatus() != 1){
            throw new LockedAccountException("账号被锁定不允许登录");
        }
        //6.封装shiro中需要的权限对象,包括用户名 密码 以及当前用户对象交给shiro返回
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userName, password, this.getName());
        return info;
    }
}

其他Controller方法需要做权限验证时,可以在上面加注解@RequiresPermissions("sys:product:add")

括号里是权限字符串,用冒号连接

shiro注解用在Service和Controller层,但是如果Service层有事务注解,那么shiro注解要放在Controller层。因为两个代理对象在类型转换时会出现异常。

https://www.cnblogs.com/huangruiwu/p/15410382.html

 

 

 

2、接口获取用户名,密码生成UsernamePasswordToken并提交认证:

@Controller
@RequestMapping("/api")
public class ApiController {
 
    @Autowired
    SysMenuService sysMenuService;
 
    @RequestMapping("/login")
    @ResponseBody
    public ResponseVO login(String username, String password) {
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        //获取当前的Subject
        Subject currentUser = SecurityUtils.getSubject();
        try {
            // 在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
            // 每个Realm都能在必要时对提交的AuthenticationTokens作出反应
            // 所以这一步在调用login(token)方法时,它会走到xxRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法
            currentUser.login(token);
 
            //认证通过,将菜单信息返回给前端展示
            if (currentUser.isAuthenticated()) {
                MenuSystem menuSystem = sysMenuService.findMenuTree();
                Gson gson = new Gson();
                String menuJson = gson.toJson(menuSystem, MenuSystem.class);
                return ResultUtil.success("登录成功!", menuJson);
            }
        } catch (UnknownAccountException e1) {
            e1.printStackTrace();
            return ResultUtil.error("用户名不存在!");
        } catch (IncorrectCredentialsException e2) {
            e2.printStackTrace();
            return ResultUtil.error("密码输入错误!");
        } catch (Exception e) {
            e.printStackTrace();
            return ResultUtil.error(e.getMessage());
        }
        return ResultUtil.error("登录失败!");
    }

说明:这里的菜单数据并没有使用shiro标签来实现,因为layuimini的菜单渲染是通过json数据的形式来实现的,所以这里我也是将菜单数据转换成了json给前端。

如果认证通过,那么通过subject.isAuthenticated()返回的结果就会是true,我们就可以认为登录成功了,此时,可以就可以将对应的菜单信息传回给前端渲染展示了。

https://blog.csdn.net/superyu1992/article/details/125915866

https://blog.csdn.net/superyu1992/article/details/126014248

https://blog.csdn.net/superyu1992/article/details/126058351

 

https://blog.51cto.com/wyait/2082803

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章