springboot项目整合shiro的简单实现(一)

最近在学习shiro框架的使用,在网上找了个免费的shiro视频学习,然后整合进springboot项目中,这里只是实现了登录验证与简单的权限验证功能demo,暂时没有添加cache缓存功能。这里做一个记录。

shiro视频学习网站:https://www.imooc.com/video/16949

shiro内置两个realm ,iniRealm和jdbcRealm,但是一般我们都自定义realm

@Service
public class ShiroRealm extends AuthorizingRealm {

    @Resource
    private UserMapper userMapper;

    /**
     * * 获取登录用户的权限信息并进行封装.
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取登录用户信息
        User user= (User) principalCollection.getPrimaryPrincipal();
        //查询数据库获取用户角色并进行校验
        List<String> roleName=userMapper.selectRolesByUserId(user.getId());
        if (roleName==null || roleName.size()==0)
            throw new AuthorizationException();
        Set<String> roles= new HashSet<>();
        for (String role: roleName) {
            roles.add(role);
        }
        //查询数据库获取用户权限
        List<String> pers=userMapper.selectPermissionByUserId(user.getId());
        if (pers==null||pers.size()==0)
            throw new AuthorizationException();
        Set<String> permissions=new HashSet<>();
        for (String per : pers) {
            permissions.add(per);
        }
        //构建授权对象
        SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(roles);//设置用户角色
        simpleAuthorizationInfo.setStringPermissions(permissions);//设置用户权限
        return simpleAuthorizationInfo;
    }

    /**
     * 通过此方法获取用户认证信息,并进行封装,然后返回给
     * SecurityManager对象
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //通过登录时提交的token获取用户名
        String username= (String) authenticationToken.getPrincipal();
        //在数据库中根据查询用户是否存在
        User user=userMapper.selectUserByUserName(username);
        //如果用户不存在,抛出异常
        if (user==null){
            throw new UnknownAccountException();
        }
        //如果用户存在,封装认证信息
        SimpleAuthenticationInfo
                simpleAuthenticationInfo=new SimpleAuthenticationInfo(user,
                                                    user.getPassword(), ByteSource.Util.bytes("mark"),getName());
        return simpleAuthenticationInfo;
    }
}

再配置shiro初始化配置与过滤器,因为我做的是springboot项目,所以是创建ShiroConfig配置类就行。

@Configuration
public class ShiroConfig {

    /**
     * 配置SecurityManager对象(shiro核心安全管理器对象)
     * @param shiroRealm
     * @return
     */
    @Bean
    public SecurityManager securityManager(ShiroRealm shiroRealm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

        //构建凭证匹配对象
        HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");//设置加密方式
        matcher.setHashIterations(1);//设置加密次数

        shiroRealm.setCredentialsMatcher(matcher);

        defaultWebSecurityManager.setRealm(shiroRealm);

        return defaultWebSecurityManager;
    }

    /**
     *      *   配置ShiroFilterFactoryBean对象,通过此对象
     *      *   创建过滤器工厂,并指定过滤规则
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String,String> map=new LinkedHashMap<>();
        map.put("/index/login","anon");
        map.put("/user/index","anon");
        map.put("/user/login","anon");
        map.put("/**","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    //===========授权配置============
    /**
     * spring 框架管理此对象时,会基于此对象管理
     * Shiro框架中相关API对象的生命周期
     */
    @Bean //<bean id="" class="">
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     *    配置Advisor对象,此对象中会对切入点,通知等对象进行
     *    相关描述,后续DefaultAdvisorAutoProxyCreator对象
     *    会基于描述,为目标对象创建代理对象
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor
    authorizationAttributeSourceAdvisor(
            SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor=
                new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
}

查询数据库的操作,实体类自己创建,数据库在最后

@Mapper
public interface UserMapper {
    @Select("select * from user where username=#{username}")
    User selectUserByUserName(String username);

    @Select("select role_name from roles where id in(select role_id from user_role where user_id=#{id})")
    List<String> selectRolesByUserId(int id);

    @Select("select permission_name from permission where id in (select permission_id from role_permission where role_id in (select role_id from user_role where user_id=#{id}))")
    List<String> selectPermissionByUserId(int id);


}

抛出异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(RuntimeException.class)
    public JsonResult doHandleRuntimeException(RuntimeException e){
        e.printStackTrace();
        return new JsonResult(e.getMessage());
    }

    @ExceptionHandler(ShiroException.class)
    @ResponseBody
    public JsonResult doHandleShiroException(ShiroException e){
        JsonResult result = new JsonResult();
        result.setState(0);
        if(e instanceof UnknownAccountException) {
            result.setMessage("账户不存在");
        }else if(e instanceof LockedAccountException) {
            result.setMessage("账户已被禁用");
        }else if(e instanceof IncorrectCredentialsException) {
            result.setMessage("密码不正确");
        }else if(e instanceof AuthorizationException) {
            result.setMessage("没有此操作权限");
        }else {
            result.setMessage("系统维护中");
        }
        e.printStackTrace();
        return result;
    }
}

JsonResult 是我对返回前端json格式数据的封装

@Data
public class JsonResult implements Serializable {

    /*状态码*/
    private int state = 1;//1.表示SUCCESS,0.表示ERROR

    /*状态信息*/
    private String message = "ok";

    /*正确数据*/
    private Object data;

    public JsonResult(String message) {
        this.message = message;
    }

    public JsonResult(Object data) {
        this.data = data;
    }

    public JsonResult(int state, String message) {
        this.state = state;
        this.message = message;
    }

    public JsonResult(Throwable e) {
        this.state = 0;
        this.message = e.getMessage();
    }

    public JsonResult() {
        super();
    }
}

实现controller控制类,创建测试接口

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/index")
    public String index(){

        return "login";
    }

    @RequestMapping("/login")
    @ResponseBody
    public JsonResult login(User user){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token=new UsernamePasswordToken(user.getUsername(),user.getPassword());
        subject.login(token);

        return new JsonResult(token);
    }

    //根据角色做权限验证
    @RequiresRoles(value = {"admin","vip"},logical = Logical.OR)
    @RequestMapping("/testRoles")
    @ResponseBody
    public String testRoles(){

        return "success admin";
    }

    //根据权限进行shiro验证
    @RequiresPermissions("sys:select")
    @RequestMapping("/testPermission")
    @ResponseBody
    public String testPermission(){

        return "success testPermission";
    }

}

测试接口:
http://localhost:8083/user/index
在这里插入图片描述
登录后进行角色权限测试:http://localhost:8083/user/testRoles
在这里插入图片描述

把这个demo上传到github中了,可以直接下载运行

github: https://github.com/sunyucheng123/shiro_demo.git

sql数据库不知道为什么不能导入进来,如果想看可以直接去GitHub中查看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值