继续完善Day03的Demo Day03
1. 完善退出功能
之前登出更能写完之后,有一个登出方法跨域问题,因为前后分离,前后端不共用一个Session,而Shiro默认其他请求路径需要认证之后才可以访问,故Shiro拦截器直接将登出请求拦截。
那为什么不能直接放行呢?答案肯定是不行的,因为这里如果我们直接放行登出请求的Url是不妥的。
所以我们可以为登出写一个过滤器。
1.1 登出过滤器
@Component
public class MyFilter extends FormAuthenticationFilter {
@Resource
private RedisTemplate<String,Object> redisTemplate;
//赋值一个静态的redisTemplate
public static RedisTemplate redis;
@PostConstruct //构造时赋值
public void redisTemplate(){
redis=this.redisTemplate;
}
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
//对OPTION请求方式放行 其他的请求方式都拦截。
HttpServletRequest req= (HttpServletRequest) request;//多态 向下转型
HttpServletResponse resp= (HttpServletResponse) response;
String method = req.getMethod();
System.out.println(method);
if(RequestMethod.OPTIONS.name().equals(method)) {
return true;
}
return false;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String token = req.getHeader("token");
User o = (User)redis.opsForValue().get(token);
if (StringUtils.isBlank(token) || o == null){
resp.setCharacterEncoding("UTF-8");
CommonResult result = new CommonResult(5000, "请先登录", null);
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(resp.getWriter(),result);
return false;
}
return true;
}
}
1.2 在Shiro配置类中使用自定义过滤器
HashMap<String, Filter> filters = new HashMap<>();
filters.put("authc",new MyFilter());
shiroFilterFactoryBean.setFilters(filters);
2. 根据权限动态获取菜单
2.1 后台接口
Controller:
@RestController
@CrossOrigin
@Api(tags = "权限菜单Api")
@RequestMapping("/permission")
public class PermissionController {
@Autowired
private PermissionService permissionService;
@GetMapping("getAllPermissonByUserId")
public CommonResult getAllPermissonByUserId(){
return permissionService.findAllPermissonByUserId();
}
}
Service:
采用递归动态获取菜单及菜单下的子菜单
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionDao, Permission> implements PermissionService {
@Resource
private PermissionDao permissionDao;
@Autowired
private RedisTemplate redisTemplate;
@Override
public CommonResult findAllPermissonByUserId() {
//获取请求头的token
String key = WebUtil.getRequest().getHeader("token");
//获取redis中的用户信息
User user = (User)redisTemplate.opsForValue().get(key);
//查询所有的菜单项
List<Permission> list = permissionDao.selectByUserId(user.getId());
//得到一级菜单
ArrayList<Permission> firstMenu = new ArrayList<>();
for (Permission permission : list) {
if (permission.getPid().equals("1")){
firstMenu.add(permission);
}
}
//为一级菜单添加子菜单
for (Permission menu : firstMenu) {
menu.setChildren(findChildren(list,menu.getId()));
}
return new CommonResult(2000,"查询菜单成功",firstMenu);
}
private List<Permission> findChildren(List<Permission> permissions,String pid){
ArrayList<Permission> children = new ArrayList<>();
//如果菜单列表中有pid和传进来的pid相同的 则为对应的子菜单
for (Permission permission : permissions) {
if (permission.getPid().equals(pid)){
children.add(permission);
}
}
for (Permission child : children) {
child.setChildren(findChildren(permissions,child.getId()));
}
return children;
}
}
entity:
解决LocalDateTime无法从Redis反序列化的问题
①引入依赖
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
②实体类LocalDateTime属性上加入注解
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("acl_user")
@ApiModel(value="User对象", description="用户表")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "用户id")
private String id;
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "昵称")
private String nickName;
@ApiModelProperty(value = "用户头像")
private String salt;
@ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
private Boolean isDeleted;
@ApiModelProperty(value = "创建时间")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime gmtCreate;
@ApiModelProperty(value = "更新时间")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime gmtModified;
}
2.2 前台页面动态生成菜单
使用navMenu
<template>
<div class="navMenu">
<template v-for="navMenu in navMenus">
<!-- 最后一级菜单 -->
<el-menu-item v-if="navMenu.children.length==0"
:key="navMenu.id" :data="navMenu" :index="navMenu.path"
>
<i :class="navMenu.icon"></i>
<span slot="title">{{navMenu.name}}</span>
</el-menu-item>
<!-- 此菜单下还有子菜单 -->
<el-submenu v-if="navMenu.children.length!=0"
:key="navMenu.id" :data="navMenu" :index="navMenu.path">
<template slot="title">
<i :class="navMenu.icon"></i>
<span> {{navMenu.name}}</span>
</template>
<!-- 递归 -->
<NavMenu :navMenus="navMenu.children"></NavMenu>
</el-submenu>
</template>
</div>
</template>
<script>
export default {
name: 'NavMenu',
props: ['navMenus'],
data() {
return {}
},
methods: {}
}
</script>
<style>
</style>
前台主页代码:
<template>
<el-container class="home-container">
<!-- 头部区域 -->
<el-header>
<div>
<img src="../assets/preview.jpg" height="60px" width="60px"/>
<span>TenliTenli中心</span>
</div>
<el-button type="info" @click="logout"> 退出 </el-button>
</el-header>
<!-- 页面主体区域 -->
<el-container>
<!-- 侧边栏 -->
<el-aside width="200px">
<!-- 侧边栏菜单 -->
<el-menu
background-color="deeppink"
text-color="black"
active-text-color="skyblue">
<NavMenus :navMenus="menus"></NavMenus>
</el-menu>
</el-aside>
<!-- 主体结构 -->
<el-main>Main</el-main>
</el-container>
</el-container>
</template>
<script>
//导入NavMenu组件
import NavMenu from "../components/menu.vue";
export default {
name: "home",
components: {
//注册NavMenu组件,和上面的标签名一致
NavMenus: NavMenu
},
data(){
return{
menus:[],
}
},
created() {
this.initMenu();
},
methods:{
logout(){
var that=this;
this.$http.get("http://localhost:8081/sys/logout").then(function(resp){
sessionStorage.clear();
that.$router.push("/login")
});
},
initMenu(){
var that=this;
this.$http.get("http://localhost:8081/permission/getAllPermissonByUserId").then(function(resp){
that.menus=resp.data.result;
});
}
}
}
</script>