04 springsecurity完成vue界面的管理


前面我们了解了springboot与springsecurity的整合,也了解了springsecurity通过oauth2完成单点登录。这一节我们将看一下springsecurity在前后端分离项目中的使用,也就是其对vue界面的保护和管理。

1、环境约束

  • idea2018.1
  • maven3.6.1

2、前提约束

3、操作步骤

3.1、创建前端项目

  • 创建vue项目,假设名称为springsecurity-vue-ui
    https://www.jianshu.com/p/644eb12a8174
  • 在springsecurity-vue-ui/src文件夹下创建views文件夹
  • 在springsecurity-vue-ui/src/views文件夹下创建index.vue
<template>
  <div >
    用户名: <input type="text" v-model="loginForm.username" />
    <br><br>
    密码: <input type="text" v-model="loginForm.password" />
    <br><br>
    <input type="button" value="登录" @click="login('loginForm')"/>
  </div>
</template>
<script>
  import axios from 'axios'

  axios.defaults.withCredentials = true //跨域
  axios.defaults.timeout = 10000
  axios.defaults.headers.post['Content-Type'] = 'application/x-www=form-urlencoded'
  export default {
    data () {
      return {
        loginForm: {
          username: 'zhangli',
          password: '123456',
        }
      }
    },
    methods:{
      login: function (){
        let _this = this;
        axios.post("/login?username="+this.loginForm.username+"&password="+this.loginForm.password)
          .then(function (response) {
            if(response.data.status="200")
            {
              window.location.href="/show"
            }
          })
          .catch(function (reason) {
            console.log(reason);
          })
      }
    }
  }
</script>
  • 修改springsecurity-vue-ui/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Index from '../views/index/index' 

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    // 配置路由地址
    {
      path: '/index',
      name: 'Index',
      component: Index
    }
  ]
})
  • 修改springsecurity-vue-ui/config/index.js中的proxyTable节点:
proxyTable: {
      '/login': {
        target: 'http://localhost:8082',
        '^/login':'/login'
      },
      '/show': {
        target: 'http://localhost:8082',
        '^/show':'/show'
      },
      '/logout': {
        target: 'http://localhost:8082',
        '^/logout':'/logout'
      }
    }
  • 下载包、打包以及启动,执行以下命令:
cd springsecurity-vue-ui
# 下载包
cnpm install
# 打包
cnpm run build
# 启动
cnpm run start
  • 访问http://localhost:8080/#/index,得到以下界面:
    登录界面

3.2、创建后端项目

  • 创建一个springboot项目,假设名称为springsecurity-vue-server,pom.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>net.wanho</groupId>
    <artifactId>springsecurity_vue_server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springsecurity_vue_server</name>
    <description>Demo project for Spring Boot</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
    </dependencies>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <name>Spring Releases</name>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <name>Spring Releases</name>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

</project>
  • 在application.yml中设置端口:
server:
  port: 8082
  • 在主启动类下创建UserInfo.java以记录用户信息

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class UserInfo implements UserDetails {
    private User user;
    private List<Role> roles;

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        if (roles == null || roles.isEmpty()) {
            return new ArrayList<>();
        }

        List<GrantedAuthority> authorities = new ArrayList<>();
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
        }
        return authorities;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

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

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

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

    @Override
    public boolean isEnabled() {
        return true;
    }

    public static class Role implements Serializable {
        private long id;
        private String name;

        public Role(long id, String name) {
            this.id = id;
            this.name = name;
        }

        public Role() {
        }

        public long getId() {
            return id;
        }

        public void setId(long id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    public static class User implements Serializable {
        private Long id;
        private String username;
        private String password;

        public User(Long id, String username, String password) {
            this.id = id;
            this.username = username;
            this.password = password;
        }

        public User() {
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }
}
  • 在主启动类下创建CorsConfig.java以完成跨域:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedMethods("*")
                .allowedHeaders("*")
                .allowedOrigins("*");
    }
}
  • 在主启动类下创建MyUserDetailService.java以获取用户信息,注意,我们这边的用户信息是写死的。

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class MyUserDetailService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserInfo.User user = new UserInfo.User();
        user.setUsername("zhangli");
        user.setPassword("123456");
        List<UserInfo.Role> list = new ArrayList<>();
        UserInfo.Role role = new UserInfo.Role(1, "USER");
        list.add(role);
        UserInfo userDetail = new UserInfo();
        userDetail.setRoles(list);
        userDetail.setUser(user);
        if (userDetail == null) {
            throw new UsernameNotFoundException("Not found username:" + username);
        }
        return userDetail;
    }
}
  • 在主启动类下创建MyAuthenticationProvider.java以驱动MyUserDetailService.java

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;

@Component
public class MyAuthenticationProvider implements AuthenticationProvider {

    @Resource
    private UserDetailsService userDetailService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String userName = authentication.getName();// 这个获取表单输入中返回的用户名;
        String password = (String) authentication.getCredentials();// 这个是表单中输入的密码;
        UserInfo userInfo = (UserInfo) userDetailService.loadUserByUsername(userName); // 这里调用我们的自己写的获取用户的方法;
        if (userInfo == null) {
            throw new BadCredentialsException("用户名不存在");
        }
        if (!userInfo.getPassword().equals(password)) {
            throw new BadCredentialsException("密码不正确");
        }
        Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
        return new UsernamePasswordAuthenticationToken(userInfo, password, authorities);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}
  • 在主启动类下创建WebSecurityConfig.java以设置web安全

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Resource
    MyAuthenticationProvider authenticationProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                // 对登录注册要允许匿名访问;
                .antMatchers("/login").permitAll()
                // 其他的路径都要登录之后具备USER角色
                .antMatchers("/**").hasRole("USER")
                //这里配置的loginProcessingUrl为页面中对应表单的 action ,该请求为 post,并设置可匿名访问
                .and().formLogin().loginProcessingUrl("/login").permitAll()
                //登录成功后的返回结果
                .successHandler(new AuthenticationSuccessHandlerImpl())
                //登录失败后的返回结果
                .failureHandler(new AuthenticationFailureHandlerImpl())
                //这里配置的logoutUrl为登出接口,并设置可匿名访问
                .and().logout().logoutUrl("/logout").permitAll()
                //登出后的返回结果
                .logoutSuccessHandler(new LogoutSuccessHandlerImpl())
                //这里配置的为当未登录访问受保护资源时,返回json,并且让springsecurity自带的登录界面失效
                .and().exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPointHandler());
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }

    //定义登陆成功返回信息
    private class AuthenticationSuccessHandlerImpl extends SimpleUrlAuthenticationSuccessHandler {
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
            response.setContentType("application/json;charset=utf-8");
            UserInfo userInfo = (UserInfo) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            PrintWriter out = response.getWriter();
            out.write("{\"status\":\"200\",\"msg\":\"登录成功\"}");
            out.flush();
            out.close();
        }
    }

    //定义登出成功返回信息
    private class LogoutSuccessHandlerImpl extends SimpleUrlLogoutSuccessHandler {

        public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
                                    Authentication authentication) throws IOException, ServletException {
            response.setContentType("application/json;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.write("{\"status\":\"200\",\"msg\":\"登出成功\"}");
            out.flush();
            out.close();
        }
    }

    //定义登陆失败返回信息
    private class AuthenticationFailureHandlerImpl extends SimpleUrlAuthenticationFailureHandler {
        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
            response.setContentType("application/json;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.write("{\"status\":\"100\",\"msg\":\"请检查用户名、密码或验证码是否正确\"}");
            out.flush();
            out.close();
        }
    }

    public class AuthenticationEntryPointHandler implements AuthenticationEntryPoint {
        @Override
        public void commence(HttpServletRequest httpServletRequest, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
            response.sendRedirect("http://localhost:8080/#/index");
        }
    }
}
  • 在主启动下创建UserController.java以提供api
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/show")
    public JSONObject show(){
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("status","200");
        jsonObject.put("data","this is the data");
        return jsonObject;
    }
}
  • 启动springboot

3.3、测试

  • 访问http://localhost:8080/#/index,点击“登录”,得到以下页面
    登陆成功之后访问/show
    注意,这里本应该是个页面,但作者只提供了api访问的响应结果
  • 打开一个新的标签页,访问http://localhost:8080/#/logout,得到以下页面
    访问登出api成功的响应
  • 再次刷新之前的http://localhost:8080/show,则又重新显示登录页面。
    以上就是springsecurity对vue界面的保护和管理。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM