SpringBoot + Spring Cloud +Vue 管理系统后台搭建(九、用户认证和授权)

SpringCloud搭建授权中心实现用户登录功能(上) 目录 本文介绍 框架搭建 引入JWT测试类 本文介绍 本篇我们先搭建授权中心的基本框架,已经引入JWT认证的测试类 框架搭建 由于jwt认证我们也有可能在其他微服务项目调用到,所以我们把它抽取成一个微服务放在auth-common里,然后整个授权中心其他业务逻辑我们放在auth-service里,他们共同组成授权中心这个微服务auth。 ... 阅读详情

安全框架我们使用JWT(Json Web Token)和Spring Security

JWT官网:https://jwt.io/introduction

Spring Security官网:https://spring.io/projects/spring-security

Spring Security教程:https://www.w3cschool.cn/springsecurity/

第一步、添加pom依赖

在mango-admin的pom文件中添加Spring Security 和 JWT 依赖包

<!--   Spring Security    -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
   <version>2.4.4</version>
</dependency>

<!--   JWT    -->
<dependency>
   <groupId>io.jsonwebtoken</groupId>
   <artifactId>jjwt</artifactId>
   <version>0.9.1</version>
</dependency>

第二步、添加配置类

新建security包

登录认证过滤器

在包下添加登录认证过滤器JwtAuthenticationFilter 并继承 BasicAuthenticationFilter

重写doFilterInternal进行token校验

/**
 * 登录认证过滤器
 * @author Louis
 * @date Jan 14, 2019
 */
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

   
   @Autowired
    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
       // 获取token, 并检查登录状态
        SecurityUtils.checkAuthentication(request);
        chain.doFilter(request, response);
    }
    
}

我们把验证逻辑放到SecurityUtils 的checkAuthentication方法中,checkAuthentication通过JwtTokenUtils的方法获取认证信息并保存到SpringSecurity上下文

JwtTokenUtils.java
/**
 * JWT工具类
 * @author Louis
 * @date Jan 14, 2019
 */
public class JwtTokenUtils implements Serializable {

   private static final long serialVersionUID = 1L;
   
   /**
    * 用户名称
    */
   private static final String USERNAME = Claims.SUBJECT;
   /**
    * 创建时间
    */
   private static final String CREATED = "created";
   /**
    * 权限列表
    */
   private static final String AUTHORITIES = "authorities";
   /**
     * 密钥
     */
    private static final String SECRET = "abcdefgh";
    /**
     * 有效期12小时
     */
    private static final long EXPIRE_TIME = 12 * 60 * 60 * 1000;

    /**
    * 生成令牌
    *
    * @param authentication 用户
    * @return 令牌
    */
   public static String generateToken(Authentication authentication) {
       Map<String, Object> claims = new HashMap<>(3);
       claims.put(USERNAME, SecurityUtils.getUsername(authentication));
       claims.put(CREATED, new Date());
       claims.put(AUTHORITIES, authentication.getAuthorities());
       return generateToken(claims);
   }

   /**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    private static String generateToken(Map<String, Object> claims) {
        Date expirationDate = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        return Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, SECRET).compact();
    }

    /**
    * 从令牌中获取用户名
    *
    * @param token 令牌
    * @return 用户名
    */
   public static String getUsernameFromToken(String token) {
       String username;
       try {
           Claims claims = getClaimsFromToken(token);
           username = claims.getSubject();
       } catch (Exception e) {
           username = null;
       }
       return username;
   }
   
   /**
    * 根据请求令牌获取登录认证信息
    * @param  request
    * @return 用户名
    */
   public static Authentication getAuthenticationeFromToken(HttpServletRequest request) {
      Authentication authentication = null;
      // 获取请求携带的令牌
      String token = JwtTokenUtils.getToken(request);
      if(token != null) {
         // 请求令牌不能为空
         if(SecurityUtils.getAuthentication() == null) {
            // 上下文中Authentication为空
            Claims claims = getClaimsFromToken(token);
            if(claims == null) {
               return null;
            }
            String username = claims.getSubject();
            if(username == null) {
               return null;
            }
            if(isTokenExpired(token)) {
               return null;
            }
            Object authors = claims.get(AUTHORITIES);
            List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
            if (authors != null && authors instanceof List) {
               for (Object object : (List) authors) {
                  authorities.add(new GrantedAuthorityImpl((String) ((Map) object).get("authority")));
               }
            }
            authentication = new JwtAuthenticatioToken(username, null, authorities, token);
         } else {
            if(validateToken(token, SecurityUtils.getUsername())) {
               // 如果上下文中Authentication非空,且请求令牌合法,直接返回当前登录认证信息
               authentication = SecurityUtils.getAuthentication();
            }
         }
      }
      return authentication;
   }

   /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    private static Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    /**
    * 验证令牌
    * @param token
    * @param username
    * @return
    */
   public static Boolean validateToken(String token, String username) {
       String userName = getUsernameFromToken(token);
       return (userName.equals(username) && !isTokenExpired(token));
   }

   /**
    * 刷新令牌
    * @param token
    * @return
    */
   public static String refreshToken(String token) {
       String refreshedToken;
       try {
           Claims claims = getClaimsFromToken(token);
           claims.put(CREATED, new Date());
           refreshedToken = generateToken(claims);
       } catch (Exception e) {
           refreshedToken = null;
       }
       return refreshedToken;
   }

   /**
     * 判断令牌是否过期
     *
     * @param token 令牌
     * @return 是否过期
     */
    public static Boolean isTokenExpired(String token) {
        try {
            Claims claims = getClaimsFromToken(token);
            Date expiration = claims.getExpiration();
            return expiration.before(new Date());
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取请求token
     * @param request
     * @return
     */
    public static String getToken(HttpServletRequest request) {
       String token = request.getHeader("Authorization");
        String tokenHead = "Bearer ";
        if(token == null) {
           token = request.getHeader("token");
        } else if(token.contains(tokenHead)){
           token = token.substring(tokenHead.length());
        } 
        if("".equals(token)) {
           token = null;
        }
        return token;
    }

}

 

SecurityUtils .java

/**
 * Security相关操作
 * @author Louis
 * @date Jan 14, 2019
 */
public class SecurityUtils {

   /**
    * 系统登录认证
    * @param request
    * @param username
    * @param password
    * @param authenticationManager
    * @return
    */
   public static JwtAuthenticatioToken login(HttpServletRequest request, String username, String password, AuthenticationManager authenticationManager) {
      JwtAuthenticatioToken token = new JwtAuthenticatioToken(username, password);
      token.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
      // 执行登录认证过程
       Authentication authentication = authenticationManager.authenticate(token);
       // 认证成功存储认证信息到上下文
       SecurityContextHolder.getContext().setAuthentication(authentication);
      // 生成令牌并返回给客户端
       token.setToken(JwtTokenUtils.generateToken(authentication));
      return token;
   }

   /**
    * 获取令牌进行认证
    * @param request
    */
   public static void checkAuthentication(HttpServletRequest request) {
      // 获取令牌并根据令牌获取登录认证信息
      Authentication authentication = JwtTokenUtils.getAuthenticationeFromToken(request);
      // 设置登录认证信息到上下文
      SecurityContextHolder.getContext().setAuthentication(authentication);
   }

   /**
    * 获取当前用户名
    * @return
    */
   public static String getUsername() {
      String username = null;
      Authentication authentication = getAuthentication();
      if(authentication != null) {
         Object principal = authentication.getPrincipal();
         if(principal != null && principal instanceof UserDetails) {
            username = ((UserDetails) principal).getUsername();
         }
      }
      return username;
   }
   
   /**
    * 获取用户名
    * @return
    */
   public static String getUsername(Authentication authentication) {
      String username = null;
      if(authentication != null) {
         Object principal = authentication.getPrincipal();
         if(principal != null && principal instanceof UserDetails) {
            username = ((UserDetails) principal).getUsername();
         }
      }
      return username;
   }
   
   /**
    * 获取当前登录信息
    * @return
    */
   public static Authentication getAuthentication() {
      if(SecurityContextHolder.getContext() == null) {
         return null;
      }
      Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
      return authentication;
   }
   
}

在config包下添加Spring Security配置类WebSecurityConfig.java

主要进行安全相关配置,如URL匹配策略、认证过滤、开启权限认证注解等

/**
 * Spring Security配置
 * @author Louis
 * @date Jan 14, 2019
 */
@Configuration
@EnableWebSecurity // 开启Spring Security 
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启权限注解,如:@PreAuthorize注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;
    
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 使用自定义身份验证组件
        auth.authenticationProvider(new JwtAuthenticationProvider(userDetailsService));
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 禁用 csrf, 由于使用的是JWT,我们这里不需要csrf
        http.cors().and().csrf().disable()
          .authorizeRequests()
          // 跨域预检请求
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            // web jars
            .antMatchers("/webjars/**").permitAll()
            // 查看SQL监控(druid)
            .antMatchers("/druid/**").permitAll()
            // 首页和登录页面
            .antMatchers("/").permitAll()
            .antMatchers("/login").permitAll()
            // swagger
            .antMatchers("/swagger-ui.html").permitAll()
            .antMatchers("/swagger-resources/**").permitAll()
            .antMatchers("/v2/api-docs").permitAll()
            .antMatchers("/webjars/springfox-swagger-ui/**").permitAll()
            // 验证码
            .antMatchers("/captcha.jpg**").permitAll()
            // 服务监控
            .antMatchers("/actuator/**").permitAll()
            // 其他所有请求需要身份认证
            .anyRequest().authenticated();
        // 退出登录处理器
        http.logout().logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler());
        // token验证过滤器
        http.addFilterBefore(new JwtAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManager() throws Exception {
       return super.authenticationManager();
    }
    
}

身份验证类

在Security包下新建JwtAuthenticationProvider类并继承DaoAuthenticationProvider

重写additionalAuthenticationChecks方法来进行密码匹配,我们这里没有使用默认的密码认证器(我们使用的盐salt来对密码加密,默认密码认证器没有加盐)

JwtAuthenticationProvider.java

/**
 * 身份验证提供者
 * @author Louis
 * @date Jan 14, 2019
 */
public class JwtAuthenticationProvider extends DaoAuthenticationProvider {

    public JwtAuthenticationProvider(UserDetailsService userDetailsService) {
        setUserDetailsService(userDetailsService);
    }

    @Override
   protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
         throws AuthenticationException {
      if (authentication.getCredentials() == null) {
         logger.debug("Authentication failed: no credentials provided");
         throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
      }

      String presentedPassword = authentication.getCredentials().toString();
      String salt = ((JwtUserDetails) userDetails).getSalt();
      // 覆写密码验证逻辑
      if (!new PasswordEncoder(salt).matches(userDetails.getPassword(), presentedPassword)) {
         logger.debug("Authentication failed: password does not match stored value");
         throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
      }
   }

}

认证信息查询

在security包下新建UserDetailsServiceImpl类实现UserDetailsService

重新其中的loadUserByUsername,查询用户的密码和权限信息封装到JwtUserDetails中

JwtUserDetails类需要实现UserDetails,是对认证信息的封装,包含用户名、密码、加密盐和权限信息

JwtUserDetails.java

/**
 * 安全用户模型
 * @author Louis
 * @date Jan 14, 2019
 */
public class JwtUserDetails implements UserDetails {

   private static final long serialVersionUID = 1L;
   
   private String username;
    private String password;
    private String salt;
    private Collection<? extends GrantedAuthority> authorities;

    JwtUserDetails(String username, String password, String salt, Collection<? extends GrantedAuthority> authorities) {
        this.username = username;
        this.password = password;
        this.salt = salt;
        this.authorities = authorities;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @JsonIgnore
    @Override
    public String getPassword() {
        return password;
    }

    public String getSalt() {
      return salt;
   }
    
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @JsonIgnore
    @Override
    public boolean isEnabled() {
        return true;
    }
}
UserDetailsServiceImpl.java
/**
 * 用户登录认证信息查询
 * @author Louis
 * @date Jan 14, 2019
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private SysUserService sysUserService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser user = sysUserService.findByName(username);
        if (user == null) {
            throw new UsernameNotFoundException("该用户不存在");
        }
        // 用户权限列表,根据用户拥有的权限标识与如 @PreAuthorize("hasAuthority('sys:menu:view')") 标注的接口对比,决定是否可以调用接口
        Set<String> permissions = sysUserService.findPermissions(user.getName());
        List<GrantedAuthority> grantedAuthorities = permissions.stream().map(GrantedAuthorityImpl::new).collect(Collectors.toList());
        return new JwtUserDetails(user.getName(), user.getPassword(), user.getSalt(), grantedAuthorities);
    }
}

权限分装类

在security包下新建GrantedAuthorityImpl类实现GrantedAuthority是对权限的封装,内部包含一个字符串类型的权限标识authority,

对应菜单表的perms字段的权限字符串,比如用户管理新增权限标志sys:user:add

/**
 * 权限封装
 * @author Louis
 * @date Jan 14, 2019
 */
public class GrantedAuthorityImpl implements GrantedAuthority {
   
   private static final long serialVersionUID = 1L;

   private String authority;

    public GrantedAuthorityImpl(String authority) {
        this.authority = authority;
    }

    public void setAuthority(String authority) {
        this.authority = authority;
    }

    @Override
    public String getAuthority() {
        return this.authority;
    }
}

 

添加权限注解

spring security提供了权限注解@PreAuthorize来保护后台接口免受非法访问

这里我们以字典模块为例,其他模块同理

SysDictController.java
/**
 * 字典控制器
 * @author Louis
 * @date Jan 13, 2019
 */
@RestController
@RequestMapping("dict")
public class SysDictController {

   @Autowired
   private SysDictService sysDictService;
   //用户必须同事拥有添加和修改权限才有权限
   @PreAuthorize("hasAuthority('sys:dict:add') AND hasAuthority('sys:dict:edit')")
   @PostMapping(value="/save")
   public HttpResult save(@RequestBody SysDict record) {
      return HttpResult.ok(sysDictService.save(record));
   }

   @PreAuthorize("hasAuthority('sys:dict:delete')")
   @PostMapping(value="/delete")
   public HttpResult delete(@RequestBody List<SysDict> records) {
      return HttpResult.ok(sysDictService.delete(records));
   }

   @PreAuthorize("hasAuthority('sys:dict:view')")
   @PostMapping(value="/findPage")
   public HttpResult findPage(@RequestBody PageRequest pageRequest) {
      return HttpResult.ok(sysDictService.findPage(pageRequest));
   }
   
   @PreAuthorize("hasAuthority('sys:dict:view')")
   @GetMapping(value="/findByLable")
   public HttpResult findByLable(@RequestParam String lable) {
      return HttpResult.ok(sysDictService.findByLable(lable));
   }
}

Swagger添加令牌参数

由于我们引入的spring security 接口受到保护,需要有合法的token才能正常访问,swagger本身默认并没有,因此需要修改一些之前SwaggerConfig配置类,修改后代码

@EnableSwagger2
@Configuration
public class SwaggerConfig {
    @Bean
    public Docket createRestApi(){
        // 添加请求参数,我们这里把token作为请求头部参数传入后端
        ParameterBuilder parameterBuilder = new ParameterBuilder();
        List<Parameter> parameters = new ArrayList<Parameter>();
        parameterBuilder.name("token").description("令牌")
                .modelRef(new ModelRef("string")).parameterType("header").required(false).build();
        parameters.add(parameterBuilder.build());
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
                .apis(RequestHandlerSelectors.any()).paths(PathSelectors.any())
                .build().globalOperationParameters(parameters);
        //return  new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()).build();
    }

    private ApiInfo apiInfo(){
        return new ApiInfoBuilder().build();
    }
}

配置完启动项目,访问swagger就可以传参了

 

登录接口实现

在登录控制器中添加login接口,在其中验证验证码、用户名、密码信息,匹配成功后执行spring security的登录认证机制,登录成功后返回Token令牌凭证

/**
 * 登录接口
 */
@PostMapping(value = "/login")
public HttpResult login(@RequestBody LoginBean loginBean, HttpServletRequest request) throws IOException {
   String username = loginBean.getAccount();
   String password = loginBean.getPassword();
   String captcha = loginBean.getCaptcha();
   // 从session中获取之前保存的验证码跟前台传来的验证码进行匹配
   Object kaptcha = request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
   if(kaptcha == null){
      return HttpResult.error("验证码已失效");
   }
   if(!captcha.equals(kaptcha)){
      return HttpResult.error("验证码不正确");
   }
   // 用户信息
   SysUser user = sysUserService.findByName(username);
   // 账号不存在、密码错误
   if (user == null) {
      return HttpResult.error("账号不存在");
   }
   if (!PasswordUtils.matches(user.getSalt(), password, user.getPassword())) {
      return HttpResult.error("密码不正确");
   }
   // 账号锁定
   if (user.getStatus() == 0) {
      return HttpResult.error("账号已被锁定,请联系管理员");
   }
   // 系统登录认证
   JwtAuthenticatioToken token = SecurityUtils.login(request, username, password, authenticationManager);
   return HttpResult.ok(token);
}

登录认证逻辑我们已经封装到了上面的SecurityUtils的login方法中,认证流程大体分为以下4步

1、将用户名密码的认证信息封装到JwtAuthenticatioToken对象

2、通过调用authenticationManager.authenticate(token)执行认证流程

3、通过SecurityContextHolder将认证信息保存到Security上下文

4、JwtTokenUtils.generateToken(authentication)生成token并返回

 

新建LoginBean.java 

对登录认证信息简单封装

/**
 * 登录接口封装对象
 * @author Louis
 * @date Oct 29, 2018
 */
public class LoginBean {

   private String account;
   private String password;
   private String captcha;
   
   public String getAccount() {
      return account;
   }
   public void setAccount(String account) {
      this.account = account;
   }
   public String getPassword() {
      return password;
   }
   public void setPassword(String password) {
      this.password = password;
   }
   public String getCaptcha() {
      return captcha;
   }
   public void setCaptcha(String captcha) {
      this.captcha = captcha;
   }
   
}

令牌自定义

在Security包下新建JwtAuthenticatioToken.java继承UsernamePasswordAuthenticationToken

对令牌信息简单封装,用来作为认证和授权的信息凭证,其中token信息有JWT生成

/**
 * 自定义令牌对象
 * @author Louis
 * @date Jan 14, 2019
 */
public class JwtAuthenticatioToken extends UsernamePasswordAuthenticationToken {

   private static final long serialVersionUID = 1L;
   
   private String token;

    public JwtAuthenticatioToken(Object principal, Object credentials){
        super(principal, credentials);
    }
    
    public JwtAuthenticatioToken(Object principal, Object credentials, String token){
       super(principal, credentials);
       this.token = token;
    }

    public JwtAuthenticatioToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities, String token) {
       super(principal, credentials, authorities);
       this.token = token;
    }
    
   public String getToken() {
      return token;
   }

   public void setToken(String token) {
      this.token = token;
   }

   public static long getSerialversionuid() {
      return serialVersionUID;
   }

}

到此我们已经完成配置下面进行Swagger测试

先执行验证码生成接口获取验证码

 

然后执行登录接口,输入用户名和密码和刚生成的验证码,登录成功后返回token

 

在调用其他接口不输入token,直接403,说明我们安全校验生效

 

 

输入token在调用,可以看到执行成功

 

希望可以帮助大家,记得点赞哦

 

 

微服务系统:vue+elementui +springcloud——登录auth功能认证授权(JWT、SSO)+人员角色菜单功能+架构拦截aop功能实现 #实现目标: 登录实现-权限管理 算法步奏: json服务端实现准备、 beforeRouter、全路由设置(import页面、基础路由、模块路由)准备 api响应和请求拦截器准备、 登录把登录名换成密钥再换回来 登录的服务层同时获取token(User.login/auth)、用户对象和权限菜单的数据(user.GetInfo() json字符串)、 服务层方法调用mapper映射sql语句 到dao层、 Token、用户和权限菜单的数据写入本地sessionStorage缓存和user用户 阅读详情

相关推荐

SpringBoot+Vue车辆管理系统开发实践

前后端分离架构是现代Web应用开发的主流模式,通过将前端Vue框架与后端SpringBoot技术栈解耦,实现了开发效率与系统性能的双重提升。这种架构的核心原理是基于RESTful API进行JSON数据交互,使前后端团队能够并行开发。在企业级应用中,结合MyBatis操作MySQL数据库,既能保持SQL灵活性又可简化数据访问层开发。车辆管理系统作为典型案例,展示了如何实现车辆信息管理、使用记录跟踪等核心功能模块。开发过程中,Swagger文档工具和Vue组件化设计显著提升了工程实践效率,而Nginx部署方案

weixin_34242331的博客 513

记录SpringSecurity jwt问题

认证、授权、鉴权和权限控制 0.jwt 加签->验签 加签参数中包含:头部()负载(用户名,创建时间)验签:客户端传值与服务端算一致,别人篡改什么?用户名? 验签成功标识?失败提示什么?@篡改 用户名。1.token 错误,根据token 解析荷载是会报错,其实这里应该把异常抛出,token错误! (业务:实际报异常:暂未登录或token已经过期,因为取了用户信息,取不到报错。不取用户不会报错,即便token错误) 验签:就是根据token 反解jwt,无token或token被篡改,回报异常,.

C18298182575的博客 1006

SpringBoot+Vue酒店管理系统开发实战

酒店管理系统作为典型的企业级应用,采用前后端分离架构实现业务数字化。SpringBoot框架通过自动配置和Starter依赖简化了Java后端开发,结合MyBatis实现灵活的数据访问。前端采用Vue.js构建响应式界面,配合Element UI组件库提升开发效率。该系统完整实现了用户权限管理(RBAC)、客房状态跟踪、订单处理等核心功能模块,采用JWT进行安全认证。项目部署使用Maven和npm工具链,数据库选用MySQL存储业务数据。这种技术组合既能满足教学需求,也符合当前企业开发的主流实践,是学习全栈

weixin_34342905的博客 450

【Apache Shiro】学习笔记——Authentication基础

从Authentication一步步学习。  先从代码开始,运行后再慢慢研究。 以下是我添加的dependecies: dependency> groupId>org.apache.shirogroupId> artifactId>shiro-coreartifactId> version>${shiro.version}

Stand by 1385

Spring Boot、 Spring Cloud 、OAuth2 的RBAC 权限管理系统分享

基于 Spring Cloud Hoxton 、Spring Boot 2.2、 OAuth2 的RBAC权限管理系统 基于数据驱动视图的理念封装 Ant Design Vue,即使没有 vue 的使用经验也能快速上手 提供 lambda 、stream api 、webflux 的生产实践 项目源码获取方式:关注本头条号,转发点赞文章之后后天私信【源码】即可获取 核心依赖 模块说明 cjlgb-cloud-platform ├── cjlgb-design-common ...

代码界的扛把子 1451

基于FPGA与红外成像的眼动追踪系统设计与实现(教学向)

本文详细介绍了基于FPGA与红外成像的眼动追踪系统设计与实现。通过红外摄像头采集图像,利用FPGA进行实时图像处理和红外瞳孔追踪,结合Verilog编程实现多目标检测与瞳孔定位。该系统适用于嵌入式视觉教学,展示了硬件搭建、算法优化及实时显示的完整流程。

g5h6i7j的博客 823

Java安全框架学习---Shiro基础

Shiro基础概念一. 权限的管理的概念1. 权限管理概念2. 身份认证概念3. 授权概念二. Shiro1. shiro概念(官网)2. shiro架构图3. Subject4. SecurityManager5. Authenticator6. Authorizer7. Realm8. SessionManager9. SessionDAO10. CacheManager11. Cryptography三. Shiro认证过程分析1. shiro中认证的关键对象2. 认证流程3. Springboot.

657

深入解析国家企业征信系统瑞数6vmp算法逆向实战

本文深入解析了国家企业征信系统所采用的双层防护机制,重点聚焦于瑞数6代vmp算法的逆向实战。文章详细拆解了从加速乐521状态码的绕过,到瑞数412挑战的核心算法还原过程,提供了通过动态Hook、日志分析进行算法逆向,并用Python实现自动化请求链的完整技术方案,旨在为安全研究与技术学习提供参考。

yellow的专栏 612

10款精选的后台管理系统,收藏吧!

1.vue2-manage 此项目是 vue + element-ui 构建的后台管理系统,是后台项目node-elm的管理系统,所有的数据都是从服务器实时获取的真实数据,具有真实的注册、登陆、管理数据、权限验证等功能。 项目地址:https://github.com/bailicangdu/vue2-manage 2.Cloud-Admin Cloud-Admin(开源项目) ...

不安分的猿人的专栏 16万+

从零构建:如何用MATLAB和SDR硬件搭建你的第一个OFDM卫星通信原型系统

本文详细介绍了如何利用MATLAB和SDR硬件从零构建OFDM卫星通信原型系统。通过核心组件选型、开发环境配置、OFDM算法实现到系统集成与优化的完整流程,帮助通信工程学生和DIY爱好者快速掌握软件无线电技术在卫星通信中的应用。特别推荐使用HackRF One和MATLAB工具箱实现高性价比的OFDM系统验证。

pz890123456的博客 378

【立创EDA-PCB设计基础】1.嘉立创EDA专业版软件安装+PCB基本概念+原理图绘制

本文详解PCB基本概念以及实现MCU最小系统原理图的绘制(原理图包括MCU芯片GD32F103C8T6、外部晶振、输出端口、USB输入口、5v转3v3稳压输出、复位按键、唤醒按键、LED)及嘉立创EDA专业版软件安装。为本专栏【立创EDA-PCB设计基础】后面章节实现PCB绘制做准备。

嵌入式阿齐Archie 3万+

Mango后台管理系统:基于Spring Boot、Spring Cloud、Vue.js和Element UI的管理利器

Spring Boot:Spring Boot是一个用于构建Java应用程序的开发框架,它简化了Spring应用程序的配置和部署。在Mango权限管理系统中,Spring Boot用于后端服务的开发和部署。Spring Cloud:Spring Cloud是一个用于构建分布式系统的框架,它提供了微服务架构所需的各种组件和服务治理功能。在Mango权限管理系统中,Spring Cloud用于实现服务的注册与发现、负载均衡和容错处理。

chenchuang0128的博客 1379

华为OD机试双机位A卷 - VLAN资源池 (C++ & Python & JAVA & JS & GO)

华为OD机试2025双机位A卷 VLAN资源池,提供Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解

qq_45776114的博客 879

DTS-SHOP技术栈揭秘:Vue管理系统与Java后台如何完美协同开发

DTS-SHOP作为一款基于SpringBoot + Vue + 微信小程序的商城系统,其技术栈的协同设计展现了现代全栈开发的精髓。这个开源项目通过前后端分离的架构,实现了高效的开发协作和可维护性,为开发者提供了一个完整的电商解决方案参考。 ## 🚀 技术架构全景解析 DTS-SHOP采用经典的三层架构设计,前端Vue管理系统与后端Java服务通过RESTful API进行通信。整个系统分为

gitblog_00270的博客 807

openlayers全面教程306+【目录】

vue+openlayers系列教程旨在为开发者提供简单快捷的示例。在每一个示例中,解释相应的API知识点。

大剑师兰特的GIS世界 2万+

用urdf给自己的ROS小车编写模型

3.3 使用urdf编写自己的ROS小车模型 3.3.1 常见的ROS小车结构有哪些? 下面就是常见的ROS小车,相信在大家的脑海里已经有了自己小车的样子,下面我和大家一起使用urdf对ros小车建模。 这里只对urdf进行简单介绍,然后就带大家使用urdf最基础的标签,建立机器人的urdf机器人模型。关于更多细节,请参看官网:http://wiki.ros.org/urdf/Tutorials 3.3.2 什么是urdf?建模的原因? 什么是urdf? URDF(Unified Robot Descri

「小白学移动机器人」一个专注分享移动机器人相关知识的公众号! 1万+

【2025最新】基于SpringBoot+Vue的Spring Cloud智慧云停车场服务管理系统管理系统源码+MyBatis+MySQL

直接拿走,意外获得200多套代码,需要的滴我【2025最新】基于SpringBoot+Vue的Spring Cloud智慧云停车场服务管理系统管理系统源码+MyBatis+MySQL(可提供说明文档(通过*AIGC*)

qq5_910946292的博客 500

[AI] 本地部署 Dify 遇到 Internal Error?一文彻底解决密码不一致引发的问题

摘要:Dify本地部署常见InternalError错误主要由配置残留或密码不一致导致,特别是修改.env文件后未同步清除数据库记录。彻底解决方案包括:1)清理Docker数据;2)删除旧配置和数据库;3)还原源代码;4)重建.env文件;5)重新初始化部署。关键提醒:记录部署路径、备份.env文件并妥善保存密码。该错误本质是配置冲突,最有效方法是完全重置而非调试,保持清晰的部署管理可避免多数InternalError问题。(149字)

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 435

SpringBoot+Vue办公管理系统开发实战

企业级应用开发中,前后端分离架构已成为主流技术方案。SpringBoot作为Java领域的明星框架,与Vue.js前端框架的组合,能够高效构建现代化管理系统。这种架构通过RESTful API实现前后端通信,利用JWT进行安全认证,采用RBAC模型管理权限。在实际工程中,SpringBoot的自动配置特性大幅简化了开发流程,而Vue的组件化开发则提升了前端代码的可维护性。办公管理系统作为典型应用场景,涵盖了用户管理、流程审批等企业核心需求,是学习全栈开发的优质实践项目。通过实现MySQL数据库设计、Elem

weixin_33923762的博客 403

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

「开源」10个优秀的SpringBoot项目,总有你喜欢的

一、mall star 数 12.7k,项目地址: https://github.com/macrozheng/mall mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。 后台管理系统包含商品管理、订单管理、会员管...

weixin_45137090的博客 5万+

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

基于Spring Cloud微服务化开发平台Cloud-Platform完整解析

小Hub领读:讲解视频也同步发布啦,记得去看哈,一键三连哇。视频讲解:https://www.bilibili.com/video/bv1SD4y1o7cN这系统,一定要学会用户-服务认...

MarkerHub的博客 4645

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

SpringBoot+Vue高校竞赛管理系统架构设计与实现

现代Web应用开发中,前后端分离架构已成为主流技术方案。SpringBoot作为Java生态的微服务框架,通过自动配置和起步依赖简化后端开发;Vue.js则以其响应式特性和组件化体系成为前端开发的首选。这种技术组合在管理系统类项目中展现显著优势,特别是在需要处理复杂业务逻辑和数据关系的场景。高校竞赛管理系统作为典型案例,采用SpringBoot提供RESTful API,结合Vue实现模块化前端,配合MySQL+MyBatis完成数据持久化,构建出高性能、易维护的全栈解决方案。系统实现过程中,RBAC权限控

weixin_30730053的博客 481

3步实现企业级权限管理系统:RuoYi-Vue快速开发框架实战指南

RuoYi-Vue是一款基于SpringBoot+Vue的前后端分离Java快速开发框架,专注于为企业提供完整的权限管理系统解决方案。在前100字的介绍中,我们深入探讨这个开源框架如何帮助企业快速构建安全可控的后台管理系统,解决权限管理、菜单控制、用户认证等核心业务需求。 ## 业务场景痛点:为什么企业需要权限管理系统? 在企业信息化建设中,权限管理是每个系统都无法回避的核心问题。传统开发模式

gitblog_00092的博客 865

SpringBoot+Vue物流管理系统开发实战

企业级应用开发中,前后端分离架构已成为主流技术方案。SpringBoot作为Java领域最流行的微服务框架,通过自动配置和Starter机制大幅简化了后端开发;Vue.js则以其响应式数据绑定和组件化特性,成为构建现代化前端界面的首选。这种技术组合在物流管理系统等业务场景中展现出显著优势,既能实现RESTful API的高效开发,又能保证用户界面的流畅交互。项目中整合MyBatis-Plus进行数据持久化、Spring Security处理权限认证、Element UI快速搭建管理界面等实践,完整呈现了全栈

weixin_30924087的博客 355

SpringBoot+Vue企业级篮球管理系统架构解析

现代企业级应用开发中,SpringBoot与Vue.js的全栈组合已成为中后台系统的黄金标准。SpringBoot通过自动配置机制快速构建生产级微服务,Vue则凭借组件化架构实现高效UI开发。在数据持久层,MyBatis框架提供了SQL可控性与开发效率的完美平衡,特别适合需要复杂查询优化的业务场景。本文以篮球联盟管理系统为例,详解如何基于SpringBoot+Vue+MyBatis技术栈实现高并发访问、数据一致性保障等企业级需求,包含球队管理、赛程排期等核心模块的MyBatis高级映射技巧与Vue状态管理实

weixin_34414196的博客 530

分享13个Spring Boot 优质开源项目!商城,ERP,管理系统…

分享13个Spring Boot 优质开源项目!商城,ERP,管理系统… 转载:https://mp.weixin.qq.com/s/UIdga3zxhqFS3Xa3rNThHw 1、mall star 数 12.7k,项目地址:https://github.com/macrozheng/mall mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyB...

Object的博客 1万+
上一篇: SpringBoot + Spring Cloud +Vue 管理系统后台搭建(八、集成kaptcha实现登录验证码)
下一篇: SpringBoot + Spring Cloud +Vue 管理系统后台搭建(十、数据备份还原)
Java程序之猿
博客等级 码龄9年 2599粉丝 140原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值