vue2+springsecurity权限系统的实现
作者:用户6125466032139
准备内容
新建项目,SpringBoot采用2.7.11,spring-boot-starter-security,vue 2.0
默认会自动启动拦截装置,可以这样取消,先这样配置一下
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
JWT 校验用户的凭证(头部,载荷,签证)
引入依赖
<!-- JWT --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.2.0</version> </dependency>
逻辑:用户登录后,请求头中加一个token参数,如果有则表示可以访问,没有就不能访问,这是一个小测试还是有点缺陷的
SpringSecurity 权限控制
一共有两个最主要拦截器
登陆验证拦截器AuthenticationProcessingFilter
资源管理拦截器AbstractSecurityInterceptor
但拦截器里面的实现需要一些组件来实现分别是
AuthenticationManager认证管理器
accessDecisionManager决策管理器等组件来支撑。
流程图解读:
用户提交用户名、密码被SecurityFilterChain中的 UsernamePasswordAuthenticationFilter 过滤器获取到,封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实 现类。
然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证 。
认证成功后, AuthenticationManager 身份管理器返回一个被填充满了信息的(包括上面提到的权 限信息, 身份信息,细节信息,但密码通常会被移除) Authentication 实例。
SecurityContextHolder 安全上下文容器将第3步填充了信息的 Authentication
通过 SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。 可以看出 AuthenticationManager接口(认证管理器)是认证相关的核心接口,也是发起认证的出发点,它的实 现类为ProviderManager。而Spring Security支持多种认证方式,因此ProviderManager维护着一个 List 列表,存放多种认证方式,最终实际的认证工作是由 AuthenticationProvider完成的。咱们知道 web表单的对应的AuthenticationProvider实现类为 DaoAuthenticationProvider,它的内部又维护着 一个UserDetailsService负责UserDetails的获取。最终 AuthenticationProvider将UserDetails填充至 Authentication。
现在关掉之前的SecurityAutoConfiguration.class,打开是不是直接跳转到了登录页面呢,无法访问接口了
配置 SpringSecurity
先说下创建token的工具类
/** * 签发JWT * * @param id 用户ID * @param subject 可以是JSON数据 尽可能少 * @param ttlMillis 不知道 * @return 结果 */ public static String createJWT(String id, String subject, long ttlMillis) { SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; // 获取当前时间毫秒 long nowMillis = System.currentTimeMillis(); // 获取当前时间日期类型 Date now = new Date(nowMillis); // 生成一个加密的key SecretKey secretKey = generalKey(); JwtBuilder builder = Jwts.builder() .setId(id) .setSubject(subject) // 主题 .setIssuer("ChiHaiKeJi2016") // 签发者 .setIssuedAt(now) // 签发时间 .signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙 if (ttlMillis >= 0) { long expMillis = nowMillis + ttlMillis; Date expDate = new Date(expMillis); builder.setExpiration(expDate); // 过期时间 } return builder.compact(); } /** * 生成jwt token * @param username 用户名 */ public static String genJwtToken(String username) { return createJWT(username, username, 60 * 60 * 1000); } /** * 生成加密Key */ public static SecretKey generalKey() { // 目前只知道这个方法生成一个key,并用base64解码 byte[] encodedKey = Base64.decode(JwtConstant.JWT_SECERT); // 目前不知道啥意思 return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES"); }
配置信息--新建SecurityConfig
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig { // 白名单 private static final String[] URL_WHITE_LIST = {"/login"}; @Resource private LoginHandler loginHandler; // 密码加密方式 @Bean protected PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { // 开启跨域 以及csrf攻击关闭 httpSecurity.cors().and().csrf().disable() // 登录登出配置 .formLogin() // 登录成功接口 .successHandler(loginHandler) // 登录失败的接口 .failureHandler(loginHandler) // .and().logout().logoutSuccessHandler() // session禁用配置 .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态,前后端分离 // 拦截规则配置 // // 白名单内容放行 .and().authorizeRequests().antMatchers(URL_WHITE_LIST).permitAll() // 需要认证 .anyRequest().authenticated(); return httpSecurity.build(); } }
配置登录失败与成功接口---新建---LoginHandler 处理类
/** * 登录成功与失败处理器 */ @Component public class LoginHandler implements AuthenticationSuccessHandler, AuthenticationFailureHandler { // 登录成功的 @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { response.setContentType("application/json;charset=UTF-8"); ServletOutputStream stream = response.getOutputStream(); // 获取token String token = JwtUtils.genJwtToken("user"); // 写入数据 stream.write(JSONUtil.toJsonStr(new Result("登录成功", token)).getBytes()); stream.flush(); stream.close(); } // 登录失败的 @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { response.setContentType("application/json;charset=UTF-8"); ServletOutputStream stream = response.getOutputStream(); String message = exception.getMessage(); if (exception instanceof BadCredentialsException) { message = "用户名或者密码错误!"; } stream.write(JSONUtil.toJsonStr(new Result(message)).getBytes(StandardCharsets.UTF_8)); stream.flush(); stream.close(); } }
在用户service实现类中自定义查询数据库
@Service public class SysUserServiceImpl implements SysUserService, UserDetailsService { @Resource private SysUserMapper sysUserMapper; // 自定义查询参数是用户名 @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { LambdaQueryWrapper<SysUser> sysUserLambdaQueryWrapper = new LambdaQueryWrapper<>(); sysUserLambdaQueryWrapper.eq(SysUser::getUsername, username); SysUser user = sysUserMapper.selectOne(sysUserLambdaQueryWrapper); if (user == null) { throw new UsernameNotFoundException("用户名或密码错误!"); } else if ("1".equals(user.getStatus())) { throw new UsernameNotFoundException("该用户已被封禁!"); } // 第三个是拥有权限 return new User(user.getUsername(), user.getPassword(), getUserAuthority()); } // 权限 private List<GrantedAuthority> getUserAuthority() { return new ArrayList<>(); } }
再来说下前端,先配置跨域
module.exports = { devServer: { host: '0.0.0.0', // 可以忽略不写 port: 8080, // 它是用来修改你打开后的端口号的 open: true, // 值为 true的话,项目启动时自动打开到浏览器里边, false不会打开 proxy: { '/api': { target: 'http://localhost:82', // 跨域请求的公共地址 ws: false, // 也可以忽略不写,不写不会影响跨域 changeOrigin: true, // 是否开启跨域,值为 true 就是开启, false 不开启 pathRewrite: { '^/api': ''// 注册全局路径, 但是在你请求的时候前面需要加上 /api } } } } }
配置axios,因为配置了跨域,这个时候可以直接写api了
import axios from 'axios' const request = axios.create({ baseURL: '/api' // 因为配置跨域了 }) // 下面这是拦截器,拦截请求,自动加token令牌 request.interceptors.request.use( config => { config.headers.token = `${localStorage.getItem('token')}` return config } ) export default request
说下如何请求前端登录接口POST请求
登录接口就是login,传入username和password就可以了
export const Login = function (data) { return request({ method: 'post', url: 'login', data: qs.stringify(data) }) }
到此这篇关于vue2+springsecurity权限系统的实现的文章就介绍到这了,更多相关vue springsecurity权限内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!