vue +security 前后段分离权限管理小demo

小咪咪 2022-10-17 05:23 31阅读 0赞

security+ vue 实现前后端分离权限

演示视频链接:
https://gulibuckets.oss-cn-shenzhen.aliyuncs.com/Action 2021-6-1 20-46-34.mp4?versionId=CAEQIxiBgICG8ceezhciIGYwOGFhNDRjYmJmZDQ3M2ZhNWNkODkxMWFjMmYwMjY3

gitee demo 地址 : https://gitee.com/wx\_c3b99916a9/vue\_security/tree/css/

第一步:跨域问题,

前后段分离,需要解决跨域 问题,像当前vue + security 解决:有以下会遇到的解决跨域的方法

第一: 使用 srping 注解 @CrossOrigin (只能解决本controller 控制器 , 或者 ,本方法跨域)

第二,全局跨域 需要写一个 过滤器 来继承 WebMvcConfigurer 接口,然后配合

  1. @Configuration
  2. public class CorsConfig implements WebMvcConfigurer {
  3. private CorsConfiguration buildConfig() {
  4. CorsConfiguration corsConfiguration = new CorsConfiguration();
  5. corsConfiguration.addAllowedOrigin("*");
  6. corsConfiguration.addAllowedHeader("*");
  7. corsConfiguration.addAllowedMethod("*");
  8. corsConfiguration.addExposedHeader("Authorization");
  9. return corsConfiguration;
  10. }
  11. @Bean
  12. public CorsFilter corsFilter() {
  13. UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  14. source.registerCorsConfiguration("/**", buildConfig());
  15. return new CorsFilter(source);
  16. }
  17. @Override
  18. public void addCorsMappings(CorsRegistry registry) {
  19. registry.addMapping("/**").allowedOriginPatterns("*")
  20. .allowCredentials(true)
  21. .allowedMethods("GET", "POST", "DELETE", "PUT")
  22. .maxAge(3600);
  23. }
  24. }

第三: security 内置解决跨域 配置

  1. public class CsrfSecurityRequestMatcher implements RequestMatcher {
  2. private final Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
  3. //设置可以放过的请求
  4. private final RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("^/.*", null);
  5. @Override
  6. public boolean matches(HttpServletRequest request) {
  7. if(allowedMethods.matcher(request.getMethod()).matches()){
  8. return false;
  9. }
  10. return !unprotectedMatcher.matches(request);
  11. }
  12. }
  13. http.cors();
  14. RequestMatcher requestMatcher = new CsrfSecurityRequestMatcher();
  15. http.csrf().requireCsrfProtectionMatcher(requestMatcher);
  16. /* 解决前端跨域的问题*/
  17. @Bean
  18. CorsConfigurationSource corsConfigurationSource() {
  19. CorsConfiguration configuration = new CorsConfiguration();
  20. configuration.addAllowedOriginPattern("*");//修改为添加而不是设置,* 最好改为实际的需要,我这是非生产配置,所以粗暴了一点
  21. configuration.addAllowedMethod("*");//修改为添加而不是设置
  22. configuration.addAllowedHeader("*");
  23. //这里很重要,起码需要允许 Access-Control-Allow-Origin
  24. configuration.setAllowCredentials(true);
  25. UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  26. source.registerCorsConfiguration("/**", configuration);
  27. return source;
  28. }

第四中:还有在 vue 中需要对 axios 进行配置拦截

后端代码编写:
  1. import com.ljm.filter.TokenAuthenticationFilter;
  2. import com.ljm.filter.TokenLoginFilter;
  3. import com.ljm.pojo.DefaultPasswordEncoder;
  4. import com.ljm.security.TokenLogoutHandler;
  5. import com.ljm.security.TokenManager;
  6. import com.ljm.security.UnauthorizedEntryPoint;
  7. import com.ljm.securitys.JwtAccessDeniedHandler;
  8. import com.ljm.service.impl.UserDetailsServiceImpl;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.beans.factory.annotation.Qualifier;
  11. import org.springframework.context.annotation.Bean;
  12. import org.springframework.context.annotation.Configuration;
  13. import org.springframework.data.redis.core.RedisTemplate;
  14. import org.springframework.security.authentication.AuthenticationManager;
  15. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  16. import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
  17. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  18. import org.springframework.security.config.annotation.web.builders.WebSecurity;
  19. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  20. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  21. import org.springframework.security.core.userdetails.UserDetailsService;
  22. import org.springframework.security.web.util.matcher.RequestMatcher;
  23. import org.springframework.web.cors.CorsConfiguration;
  24. import org.springframework.web.cors.CorsConfigurationSource;
  25. import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
  26. /** * <p> * Security配置类 * </p> * * @author qy * @since 2019-11-18 */
  27. @Configuration
  28. @EnableWebSecurity
  29. @EnableGlobalMethodSecurity(prePostEnabled = true)
  30. public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {
  31. // 查询到用户 信息 + 权限 权限编码 user:user:list, user :user: add
  32. @Autowired
  33. private UserDetailsServiceImpl userDetailsService;
  34. // token 返回 用户名 + 角色 + 密码 加密 jwt 字符串
  35. @Autowired
  36. private TokenManager tokenManager;
  37. /// 自定义密码加密方式 MD5
  38. @Qualifier("DefaultPasswordEncoder")
  39. @Autowired
  40. private DefaultPasswordEncoder defaultPasswordEncoder;
  41. // 定义返回的 redis 模板
  42. @Qualifier("redisTemplateAAA")
  43. @Autowired
  44. private RedisTemplate redisTemplate;
  45. /// 认证入口
  46. @Autowired
  47. UnauthorizedEntryPoint unauthorizedEntryPoint;
  48. @Autowired
  49. public TokenWebSecurityConfig(UserDetailsServiceImpl userDetailsService, DefaultPasswordEncoder defaultPasswordEncoder,
  50. TokenManager tokenManager, RedisTemplate redisTemplate) {
  51. this.userDetailsService = userDetailsService;
  52. this.defaultPasswordEncoder = defaultPasswordEncoder;
  53. this.tokenManager = tokenManager;
  54. this.redisTemplate = redisTemplate;
  55. }
  56. /** * 配置设置 * @param http * @throws Exception */
  57. @Override
  58. protected void configure(HttpSecurity http) throws Exception {
  59. http.exceptionHandling()
  60. // 认证入口
  61. .authenticationEntryPoint(unauthorizedEntryPoint)
  62. // .accessDeniedHandler(jwtAccessDeniedHandler)
  63. .and().csrf().disable()
  64. .authorizeRequests()
  65. .anyRequest().authenticated()
  66. /// 登出自定义链接
  67. .and().logout().logoutUrl("/userEntity/logout")
  68. /// token 处理
  69. .addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate)).and()
  70. /// 登录 成功 处理
  71. .addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate))
  72. /// 访问处理器
  73. .addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate));
  74. //自定义csrf防御
  75. // http.formLogin().loginPage("/admin/acl/login").usernameParameter("username").passwordParameter("password");
  76. http.cors();
  77. RequestMatcher requestMatcher = new CsrfSecurityRequestMatcher();
  78. http.csrf().requireCsrfProtectionMatcher(requestMatcher);
  79. }
  80. /** * 登录信息 查询权限 + 用户 * @param auth * @throws Exception */
  81. @Override
  82. public void configure(AuthenticationManagerBuilder auth) throws Exception {
  83. auth.userDetailsService(userDetailsService).passwordEncoder(defaultPasswordEncoder);
  84. }
  85. /** * 配置哪些请求不拦截 * @param web * @throws Exception "/","/login", */
  86. @Override
  87. public void configure(WebSecurity web) throws Exception {
  88. web.ignoring().antMatchers("/api/**",
  89. "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**"
  90. );
  91. }
  92. /* 解决前端跨域的问题*/
  93. @Bean
  94. CorsConfigurationSource corsConfigurationSource() {
  95. CorsConfiguration configuration = new CorsConfiguration();
  96. configuration.addAllowedOriginPattern("*");//修改为添加而不是设置,* 最好改为实际的需要,我这是非生产配置,所以粗暴了一点
  97. configuration.addAllowedMethod("*");//修改为添加而不是设置
  98. configuration.addAllowedHeader("*");
  99. //这里很重要,起码需要允许 Access-Control-Allow-Origin
  100. configuration.setAllowCredentials(true);
  101. UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  102. source.registerCorsConfiguration("/**", configuration);
  103. return source;
  104. }
  105. }

19975f5716692c6a9a62d89a88711de5.png

前端vue

1.0版本:

概括:思路和代码流程都比较简单,在后台security 配置代码中对所有的方法都允许访问,

  1. /** * 配置哪些请求不拦截 * @param web * @throws Exception "/","/login", */
  2. @Override
  3. public void configure(WebSecurity web) throws Exception {
  4. web.ignoring().antMatchers("*","/api/**",
  5. "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**"
  6. );
  7. }

前端中在加载页面是获取,后台在登录成功时放回给页面的heater (存放我们的token ),解析获取用户信息,查询角色操控权限,在vue 中的

  1. mounted: function () { ///页面加载前执行的函数 tokenname()
  2. this.tokenname()
  3. },

获取到一个list 操作集合,然后对每个集合v-for 循环 ,可以按钮就显示,不可以就不显示,这样就可以做一个简单的前后端分离权限控制

  1. <template>
  2. <div class="hello">
  3. <h1>{
  4. { msg }}</h1>
  5. <h2>使用权限页面单据</h2>
  6. <ul>
  7. <li v-for="router in routerlist">
  8. <router-link :to="router.path">{
  9. {router.piecename}}</router-link>
  10. </li>
  11. <!-- <li>--------------------------------------</li>
  12. <li>
  13. <a @click="button1()">用户权限管理 </a>
  14. </li>
  15. <li>
  16. <a @click="button2()">物质管理 </a>
  17. </li>
  18. <li>
  19. <a @click="button3()">open01 </a>
  20. </li> -->
  21. </ul>
  22. </div>
  23. </template>
  24. <script>
  25. import Cookies from 'js-cookie'
  26. export default {
  27. name: 'HelloWorld',
  28. data () {
  29. return {
  30. msg: 'Welcome to Your Vue.js App',
  31. routerlist: [
  32. { piecename: '模块01', path: '/user' },
  33. { piecename: '模块02', path: '/matter' },
  34. { piecename: '模块03', path: '/open1' }
  35. ]
  36. }
  37. },
  38. mounted: function () {
  39. this.tokenname()
  40. },
  41. methods: {
  42. tokenname () {
  43. let accessToken = Cookies.get('accessToken')
  44. console.log(accessToken)
  45. /// 查询用户名称,可以不写
  46. this.$axios.post('/userEntity/info').then((res) => {
  47. console.log(res)
  48. this.msg = res.data.message
  49. })
  50. /// 查询用户权限
  51. this.$axios.post('/userEntity/menc').then((res) => {
  52. console.log(res.data.data.list)
  53. this.msg = res.data.data.list[0].user_name
  54. this.routerlist = res.data.data.list
  55. })
  56. },
  57. button1 () {
  58. this.$router.push({ path: '/user' })
  59. },
  60. button2 () {
  61. this.$router.push({ path: '/matter' })
  62. },
  63. button3 () {
  64. this.$router.push({ path: '/open1' })
  65. }
  66. }
  67. }
  68. </script>
  69. <!-- Add "scoped" attribute to limit CSS to this component only -->
  70. <style scoped>
  71. h1,
  72. h2 {
  73. font-weight: normal;
  74. }
  75. ul {
  76. list-style-type: none;
  77. padding: 0;
  78. }
  79. li {
  80. color: #42b983;
  81. display: inline-block;
  82. margin: 0 10px;
  83. }
  84. a {
  85. cursor: default;
  86. color: #42b983;
  87. }
  88. </style>

image-20210531092001451

1.0 版本:优点:思路简单,代码流程也不是很复杂,对于数据库中权限部分要求也不高,

缺点: 没有使用到security 框架的核心效果,在处理一下比较复杂的权限的时候,系统的安全性存在很大的漏洞!!

2.0版本:

登录成功修改为以下效果

image-20210531094032260

相对于1.0 版本,在登录成功之后,页面的跳转使用的是vue 中路由器router, 点击路由跳转到时候,路径跳转完成,页面内容嵌套在主页中,不用每次跳转获取到用户信息查询权限,功能也更加的全面,后台中出一些前后端分离使用的必要测试接口,其它方法全部拦截,在security 配置中,添加了 几个过滤器处理不同的前台登录情况,方法调用情况,

前台代码;代码逻辑比较复杂,在使用axios 登录方法之后配置一个axios .js 的自定义文件来对后台返回的Response (相应)进行处理,在去查询用户的权限,==(注意返回用户权限的格式需要按照VUE 路由的数据要求)==在把生成的路由格式条件到我们 指定的路由页面中()

image-20210531100641893

生成路由结果

image-20210531101138986

  1. // 导航转成路由
  2. const menuToRoute = (menu) => {
  3. if (!menu.component) {
  4. return null
  5. }
  6. let route = {
  7. name: menu.perms,
  8. path: menu.path,
  9. meta: {
  10. icon: menu.icon,
  11. title: menu.title
  12. }
  13. }
  14. console.log(' AAAA = ' + menu.component)
  15. route.component = () => import('@/views/' + menu.component + '.vue')
  16. return route
  17. }

权限部分数据库字段解释

image-20210531101526248

vue 前端代码这里就不介绍了,下图是权限使用的大致流程

3742a79cfab43f19dd8e9369efbad627.png

发表评论

表情:
评论列表 (有 0 条评论,31人围观)

还没有评论,来说两句吧...

相关阅读