ruoyi前后端分离集成magic-api

前言

magic-api写接口非常的方便,一直想要引入项目中使用,在引入前后端不分离的springboot应用的时候,十分的简单,根据官方文档引入jar包,然后配置一下就能直接使用。因为不分离的应用,使用的是cookie来记录登录状态,浏览器默认会带上,也就不需要magic-api 做任何的权限配置,直接就能使用应用原本的拦截器对权限做限制。

但是,在前后端分离的应用中使用时,由于前后端使用的是token记录登录状态,浏览器并不会默认的携带token信息,就导致,如果不放开magic-api的ui和接口链接,就无法访问。但是拦截器里配置放开后,又无法对接口做权限限制,导致接口完全暴露,十分的不安全。

通过研究官方文档,magic-api自带的权限配置有两种,一种是将用户信息写在配置文件中,这样访问ui界面就会需要输入用户名密码进行登录。这种方式虽然能狗做到权限验证,但是实际接口还是暴露的,并没有任何权限控制。

而第二中方式,官方的文档写得比较模糊,网上查找资料,也没有看到有人写清楚怎么集成,经过一番摸索后,我成功的完成了前后端分离应用的magic-api的集成。

集成magic-api

引入jar包

首先,依据官方文档引入jar包

<dependency>
    <groupId>org.ssssssss</groupId>
    <artifactId>magic-api-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

因为使用的是ruoyi的项目,其它的都是引入了的,所以只需要引入这一个jar包就可以了

<dependency>
	<groupId>cn.hutool</groupId>
	<artifactId>hutool-all</artifactId>
	<version>5.8.10</version>
</dependency>

hutool的工具包,我平时用的比较多,里边很多工工具很方便,可以根据自己的习惯引入一些工具包

配置

配置文件根据官方文档配置,没什么好讲的

magic-api:
  web: /magic/web #ui界面访问地址
  show-sql: true #配置打印SQL
  sql-column-case: camel
  editor-config: classpath:./magic/magic-editor-config.js #编辑器配置
  response-code:
    success: 200 #执行成功的code值
    invalid: 400 #参数验证未通过的code值
    exception: 500 #执行出现异常的code值
  resource:
    location: /data/magic-api

配置过滤器放开对ui界面的链接

.antMatchers("/magic/web/**").permitAll()

这里只写了一段代码,大家根据自己的框架,找到拦截器配置的类,加上配置就可以了

编写登录实现类

根据官方文档的ui鉴权多用户登录的示例编写登录实现类
我这里是用的ruoyi的框架,登录的代码都是复制的框架类的代码来修改的
其它的框架根据自己的情况修改

@Component
public class MagicLoginDeal implements AuthorizationInterceptor{
	
	 // 令牌秘钥
    @Value("${token.secret}")
    private String secret;
    
    // 令牌有效期(默认30分钟)
    @Value("${token.expireTime}")
    private int expireTime;
	
	 @Autowired
	 private TokenService tokenService;
	 
	@Resource
	private AuthenticationManager authenticationManager;

	@Autowired
	private ISysUserService userService;
	
	@Autowired
	private RedisCache redisCache;

	/**
     * 配置是否需要登录
	 */
	@Override
	public boolean requireLogin(){
		return true;
	}
	
	/**
     * 根据Token获取User
	 */
	@Override
	public MagicUser getUserByToken(String token) throws MagicLoginException {
		
		// 从token中获取MagicUser对象
		token = token.replace(Constants.TOKEN_PREFIX, "");
		
		 try {
		 
			Claims claims = parseToken(token);
			
			 // 解析对应的权限以及用户信息
			 String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
			 String userKey = getTokenKey(uuid);
			 LoginUser user = redisCache.getCacheObject(userKey);
			 
			 //获取到用户之后,封装成magic-api的用户类
			if (user!=null) {
				return new MagicUser(user.getUserId().toString(), user.getUsername(), token ,expireTime);   
			}
			
		} catch (Exception e) {
			//ruoyi的框架里边,如果token无效的话,会抛出异常,如果不做处理的话,会被magic-api捕获导致无法进入登录页面
		}
		 
		throw new MagicLoginException("token无效");
	}

	@Override
	public MagicUser login(String username, String password) throws MagicLoginException {
		//我这里做了限制,只允许admin用户登录ui
		if(!StrUtil.equals(username, "admin")) {
			throw new MagicLoginException("未授权登录");
		}
		
		//后续代码是使用的ruoyi里原封不动的登录代码,其它框架根据自己的情况修改
		
        // 用户验证
        Authentication authentication = null;
        try
        {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
            AuthenticationContextHolder.setContext(authenticationToken);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        }
        catch (Exception e)
        {
            if (e instanceof BadCredentialsException)
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new MagicLoginException("用户名或密码不匹配");
            }
            else
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new MagicLoginException(e.getMessage());
            }
        }
        finally
        {
            AuthenticationContextHolder.clearContext();
        }
        
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());
        
        // 返回登录信息  登录成功后将用户信息封装成magic-api的用户信息
        return new MagicUser(loginUser.getUserId().toString(), username, tokenService.createToken(loginUser) , expireTime);
	}
	
	@Override
	public void logout(String token) {
		
	}
	
	/**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId)
    {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
        sysUser.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(sysUser);
    }
    
    private String getTokenKey(String uuid)
    {
        return CacheConstants.LOGIN_TOKEN_KEY + uuid;
    }
    
    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    private Claims parseToken(String token)
    {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

}

配置前端请求时携带token

var MAGIC_EDITOR_CONFIG = {
	request: {
		beforeSend: function(config){
		    // 如果是基于Cookie验证的,此处可以不配。
		    //这里的Authorization 修改为自己框架的token key
		    config.headers.Authorization = localStorage["magic-token"]; // 此处自行获取Token
		    return config;
		}
	},
    getMagicTokenValue: function(){
        return localStorage["magic-token"];
    }
}

这个文件是前面在yaml里边配置的 classpath:./magic/magic-editor-config.js
这个是magic-api的编辑器的配置文件,可以选择内置到jar里边,也可以配置使用外部文件
最终的难点在于,官方文档里边并没有写如何获取token,我console.log(window) 把所有变量输出,然后在本地缓存里边找到了后台返回的token,才能根据官方文档完成配置
下面我贴一下官方文档的代码示例

var MAGIC_EDITOR_CONFIG = {
    getMagicTokenValue: function(){
        var token = ..........; // 此处自行获取token 
        return token;
    }
}

只能说,这个写法,默认我们知道后台返回的token放哪里了

这样配置完成后,magic-api就集成完成了,可以使用框架自己的用户登录,并且接口需要携带token才能访问,这样,我们就能愉快的使用magic-api给前端写接口了

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
RuoYi是一个基于Spring Boot和Vue.js的开源框架,它采用前后端分离的架构设计,实现了数据前后端分离开发。在RuoYi中,通过前后端分离的方式,可以实现导出功能。 首先,前端负责显示数据的页面布局和交互操作。在前端页面中,可以通过调用后端接口获取需要导出的数据,并将其展示在页面上。在需要导出的地方,可以添加一个导出按钮或其他触发事件的组件,通过点击按钮或触发事件的方式,调用后端接口进行导出操作。 其次,后端负责处理导出的相关逻辑。在RuoYi的后端代码中,通常会有一个导出的控制层,负责接收前端的导出请求,并进行相应的数据处理和导出操作。后端可以通过调用某些工具类或第三方库来生成导出文件,如使用Apache POI库生成Excel文件、使用iText或PDFBox库生成PDF文件等。 最后,导出的结果可以返回给前端进行下载或其他操作。后端处理完导出逻辑后,可以将生成的导出文件保存到服务器的某个位置,然后将文件的路径返回给前端。前端根据返回的文件路径,可以通过下载链接或其他方式提供给用户进行文件下载。 总结来说,RuoYi采用前后端分离的架构,通过前端调用后端接口来实现数据的导出。在前端页面中,添加导出按钮或触发事件的组件,通过点击或触发事件的方式调用后端接口。后端处理导出逻辑后,生成导出文件并保存,然后将文件路径返回给前端进行下载或其他操作。这样可以实现RuoYi前后端分离导出功能。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值