Springboot+Vue实现在线聊天室项目目录
该聊天室为大二上学期计算机网络大作业,并且是本人第一次使用vue实现前后端分离的项目,前端架构尚未熟悉可能会出现一些不妥之处,还请大佬们指出。(本文章写于项目整体完成上线之后,所以一些细节并未写出)
pom导入springSecurity
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
编写配置文件
在config文件夹中创建注解为
@Configuration
@EnableWebSecurity
并继承WebSecurityConfigurerAdapter的配置类
其中依赖注入UserService用于密码检测,corsFilter用于跨域配置
配置http的security
其中,.sessionManagement().invalidSessionUrl("/session/invalid").用于登录权限过期时的跳转,当sesion中的信息过期时,前端再次访问会跳转到session/invalid接口。这里在前端加一个拦截器检测该接口的返回,如果出现则前端跳转到登录页面
这里配置/register、/invalid两个接口不受权限控制,为permitAll。formLogin也为permitAll,即登录、注册、过期三个接口不受权限限制。
配置http登录成功、失败、注销
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
System.out.println("登陆成功");
Map<String, Object> map = new HashMap<>();
map.put("msg", "登录成功!");
map.put("principal", authentication.getPrincipal());
resp.setContentType("application/json;charset=utf-8");
resp.setHeader("Access-Control-Allow-Origin","http://www.guoruijava.xyz");
resp.setHeader("Access-Control-Allow-Credentials", "true");
resp.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
resp.setHeader("Access-Control-Max-Age", "3600");
resp.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
PrintWriter out = resp.getWriter();
// 对象转json传输给前端
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
System.out.println("登录失败");
Map<String, Object> map = new HashMap<>();
resp.setContentType("application/json;charset=utf-8");
resp.setHeader("Access-Control-Allow-Origin", "http://www.guoruijava.xyz");
resp.setHeader("Access-Control-Allow-Credentials", "true");
resp.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");
resp.setHeader("Access-Control-Max-Age", "3600");
resp.addHeader("Access-Control-Allow-Headers", "token,accesstoken,Content-type");
System.out.println("设置resp" + resp.toString());
PrintWriter out = resp.getWriter();
if (e instanceof BadCredentialsException){
map.put("msg","账号或密码输入错误,登录失败!");
}else{
map.put("msg","出现异常,登录失败!");
}
// 对象转json传输给前端
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.permitAll()
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
Map<String, Object> map = new HashMap<>();
map.put("state", 200);
map.put("msg", "注销成功!");
resp.setContentType("application/json;charset=utf-8");
resp.setHeader("Access-Control-Allow-Origin","http://www.guoruijava.xyz");
resp.setHeader("Access-Control-Allow-Credentials", "true");
resp.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
resp.setHeader("Access-Control-Max-Age", "3600");
resp.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
PrintWriter out = resp.getWriter();
// 对象转json传输给前端
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();
}
})
.permitAll();
配置数据库的security权限
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("权限管理");
auth.userDetailsService(userService);
}
security的拦截器会调用这里userService中的loadUserByUsername方法,这个方法是实现UserDetailsService接口重写的方法
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User use = userDao.getUserByAccount(s);
if (use == null){
throw new UsernameNotFoundException("用户名不存在");
}else{
System.out.println(new User(use.getId(),use.getName(),use.getImg(),use.getAccount(),use.getPassword(),"ROLE_USER",
userDao.getMyFriends(use.getFriends().split("\\|")),userDao.getMyRooms(use.getRooms().split("\\|"))).toString());
return new User(use.getId(),use.getName(),use.getImg(),use.getAccount(),use.getPassword(),"ROLE_USER",
userDao.getMyFriends(use.getFriends().split("\\|")),userDao.getMyRooms(use.getRooms().split("\\|")));
}
}
登录成功后,由security将用户信息principal存入容器中,这个信息可以通过SecurityContextHolder.getContext().getAuthentication().getPrincipal()来获取(用于后续用户操作时获取用户的信息权限)
。这里将获取用户id作为静态方法放在UserService中
public static int getUserIdCurrent(){
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
int id = ((User)principal).getId();
return id;
}