前后端完全分离

1.大纲

1. 前置路由守卫
2. 整合shiro安全框架
3. 前端自定义指令。

2.前置路由守卫

前置路由守卫:就是在路由跳转前加上自己得一些业务代码。

//设置前置路由守卫 to:到哪个路由  from:从哪个路由来  next():放行到指定路由
router.beforeEach((to,from,next)=>{
      //获取跳转得路径
      var path = to.path;
      //判断是否为登录路由路径
      if(path==="/login"){
          console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
          //放行
          return next();
      }
      //其他路由路径 判断是否登录过
      var token = sessionStorage.getItem("token");
      if(token){
          return next();
      }
      //跳转登录
     return next("/login");
})

3.整合shiro

(1)依赖

  <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.7.0</version>
        </dependency>

(2)shiro的配置类

@Configuration
public class ShiroConfig {

    @Bean
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm());
        return securityManager;
    }

    @Bean
    public Realm realm(){
        MyRealm myRealm = new MyRealm();
        myRealm.setCredentialsMatcher(credentialsMatcher());
        return myRealm;
    }

    @Bean
    public CredentialsMatcher credentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashIterations(1024);
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        return hashedCredentialsMatcher;
    }

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean filterFactoryBean(){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager());

        //设置shiro过滤规则
        Map<String, String> map = new HashMap<>();
        map.put("/system/login","anon");
        map.put("/**","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);


        //设置未登录过滤器
        Map<String, Filter> filters = new HashMap<>();
        filters.put("authc",new LoginFilter());
        shiroFilterFactoryBean.setFilters(filters);

        return shiroFilterFactoryBean;
    }


    @Bean
    public FilterRegistrationBean<Filter> filterProxy(){
          FilterRegistrationBean<Filter> filterRegistrationBean=new FilterRegistrationBean<>();
          filterRegistrationBean.setFilter(new DelegatingFilterProxy());
          filterRegistrationBean.setName("shiroFilter");
          filterRegistrationBean.addUrlPatterns("/*");
          return filterRegistrationBean;
    }
}

(3)增加一个realm类对象

public class MyRealm extends AuthorizingRealm {

    @Autowired
    private IUserService userService;
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);
        wrapper.eq("is_deleted",0);
        User user = userService.getOne(wrapper);
        if(user!=null){
            ByteSource bytes = ByteSource.Util.bytes(user.getSalt());
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),bytes,this.getName());
            return info;
        }
        return null;
    }
}

(4)修改controller代码

 测试登录

登录成功后获取用户信息时出现如下得错误

 被shiro得拦截器给拦截器了

解决办法:

public class LoginFilter extends FormAuthenticationFilter {

    private RedisTemplate redisTemplate;  //LoginFilter必须交于spring容器来管理。

    public LoginFilter(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    //当登录成功后执行得方法,如果该方法返回false,则执行onAccessDenied
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        System.out.println(redisTemplate);
        HttpServletRequest req = (HttpServletRequest) request;
        //1.请求方式是否为OPTIONS
        String method = req.getMethod();
        if(method!=null && method.equals("OPTIONS")){
            return true;
        }

        //2.判断请求头是否有token值
        String token = req.getHeader("token");
        if(token!=null && redisTemplate.hasKey(token)){
            return true;
        }
        return false;
    }

    //未登录时调用该方法? 为什么进入没有登录方法:
    // --->第一个请求是OPTIONS,没有携带token  第二个因为前端和后端不是用得同一个session.默认shiro以sessionId为是否登录得标准
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        System.out.println("*******************************");
        return false;
    }
}

4.主页布局

<template>
        <el-container>
            <el-header>
                <span id="logo" style="display: inline-block;width: 50%;height: 100%;float: left" >
                     <a href="https://www.bilibili.com/video/BV14g41197PY/"><img src="../assets/logo.png" height="100%" width="180px"></a>
                </span>
                <span id="avatar" style="float: right">
                    <el-dropdown >
                  <span class="el-dropdown-link" style="margin-top: 10px; display: inline-block;">
                    <el-avatar ></el-avatar>
                  </span>
                    <el-dropdown-menu slot="dropdown">
                        <el-dropdown-item command="info">个人信息</el-dropdown-item>
                        <el-dropdown-item command="logout">退出登录</el-dropdown-item>
                    </el-dropdown-menu>
                </el-dropdown>
                </span>
            </el-header>
            <el-container>
                <el-aside width="200px">

                </el-aside>
                <el-main>

                </el-main>
            </el-container>
            <el-footer>Footer</el-footer>
        </el-container>
</template>

<script>
    export default {
        name: "Home",
        methods:{
              getInfo(){
                   this.$http.get("http://localhost:8808/system/user/getInfo").then(result=>{
                         console.log(result)
                   })
              }
        }
    }
</script>
<!--当前vue有效-->
<style>
    html,body,#app{
         height: 100%;
    }
    body,#app{
        padding: 0px;
        margin:0px;
    }
    .el-container{
         height: 100%;
    }
    .el-header, .el-footer {
        background-color: #1F272F;
        color: #333;
        line-height: 60px;
    }

    .el-aside {
        background-color: #545c64;
        color: #333;
        line-height: 560px;
    }
    .el-aside>.el-menu{
        border: none;
    }
    .el-main {
        background-color: #E9EEF3;
        color: #333;
        line-height: 560px;
    }

    body > .el-container {
        margin-bottom: 40px;
    }

    .el-container:nth-child(5) .el-aside,
    .el-container:nth-child(6) .el-aside {
        line-height: 260px;
    }

    .el-container:nth-child(7) .el-aside {
        line-height: 320px;
    }
</style>

 5.退出

前端:

后端:

 @GetMapping("/logout")
    public CommonResult logout(HttpServletRequest request){
        String token = request.getHeader("token");
        if(redisTemplate.hasKey(token)){
            redisTemplate.delete(token);
            return new CommonResult(2000,"退出成功",null);
        }
        return new CommonResult(5000,"无效得token",null);
    }

6.查询左侧菜单

前端:

initLeftMenu(){
                this.$http.get("/system/permission/leftMenu").then(result=>{
                      if(result.data.code===2000){
                           this.leftMenus=result.data.data;
                      }
                })
            },

后端

@Controller
@RequestMapping("/system/permission")
public class PermissionController {

    @Autowired
    private IPermissionService permissionService;

    @GetMapping("leftMenu")
    public CommonResult leftMenu(HttpServletRequest request){
        String token = request.getHeader("token");
        return permissionService.findPermissionByUserId(token);
    }

}

业务层

@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements IPermissionService {

    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public CommonResult findPermissionByUserId(String token) {
        //根据token获取用户信息
        ValueOperations forValue = redisTemplate.opsForValue();
        User o = (User) forValue.get(token);
        String id = o.getId();
        //根据用户id查询该用户具有得权限。
        List<Permission> permissionList = permissionMapper.selectByUserId(id);
        //设置层级关系
        List<Permission> firstMenus = new ArrayList<>();
        for (Permission first : permissionList) {
            //int
            if (first.getPid().equals("1")) {
                firstMenus.add(first);
            }
        }


        //为一级菜单设置二级菜单
        for (Permission first : firstMenus) {
            //根据一级菜单id 查询 该菜单得二级菜单。如果出现不确定有几级菜单 那么我们可以使用方法得递归调用
            first.setChildren(findChildren(permissionList, first.getId()));

        }

        return new CommonResult(2000,"查询成功",firstMenus);
    }

    //方法递归
    private List<Permission> findChildren(List<Permission> permissionList, String id) {
        List<Permission> children = new ArrayList<>();
        for (Permission p : permissionList) {
            if (p.getPid().equals(id)) {
                children.add(p);
            }
        }


        for (Permission child : children) {
            child.setChildren(findChildren(permissionList, child.getId()));
        }

        return children;

    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值