添加spring security

This commit is contained in:
2020-07-15 19:05:21 +08:00
parent 852c3b2b61
commit 8b04c70a07
11 changed files with 416 additions and 98 deletions
@@ -0,0 +1,98 @@
package com.yaoyuan.jiscuss.config;
import com.yaoyuan.jiscuss.handler.CustomAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
prePostEnabled :决定Spring Security的前注解是否可用 [@PreAuthorize,@PostAuthorize,..]
secureEnabled : 决定是否Spring Security的保障注解 [@Secured] 是否可用
jsr250Enabled :决定 JSR-250 annotations 注解[@RolesAllowed..] 是否可用.
*/
@Configurable
@EnableWebSecurity
//开启 Spring Security 方法级安全注解 @EnableGlobalMethodSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true,jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private CustomAccessDeniedHandler customAccessDeniedHandler;
@Qualifier("userDetailServiceImpl")
@Autowired
private UserDetailsService userDetailsService;
/**
* 静态资源设置
*/
@Override
public void configure(WebSecurity webSecurity) {
//不拦截静态资源,所有用户均可访问的资源
webSecurity.ignoring().antMatchers(
"/",
"/css/**",
"/js/**",
"/images/**",
"/static/**",
"/index/**"
);
}
/**
* http请求设置
*/
@Override
public void configure(HttpSecurity http) throws Exception {
//http.csrf().disable(); //注释就是使用 csrf 功能
http.headers().frameOptions().disable();//解决 in a frame because it set 'X-Frame-Options' to 'DENY' 问题
//http.anonymous().disable();
http.authorizeRequests()
.antMatchers("/login/**","/initUserData")//不拦截登录相关方法
.permitAll()
//.antMatchers("/user").hasRole("ADMIN") // user接口只有ADMIN角色的可以访问
// .anyRequest()
// .authenticated()// 任何尚未匹配的URL只需要验证用户即可访问
.anyRequest()
.access("@rbacPermission.hasPermission(request, authentication)")//根据账号权限访问
.and()
.formLogin()
// .loginPage("/")
.loginPage("/login") //登录请求页
.loginProcessingUrl("/login") //登录POST请求路径
.usernameParameter("username") //登录用户名参数
.passwordParameter("password") //登录密码参数
.defaultSuccessUrl("/") //默认登录成功页面
.and()
.exceptionHandling()
.accessDeniedHandler(customAccessDeniedHandler) //无权限处理器
.and()
.logout()
.logoutSuccessUrl("/login?logout"); //退出登录成功URL
}
/**
* 自定义获取用户信息接口
*/
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
/**
* 密码加密算法
* @return
*/
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@@ -11,17 +11,20 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
@@ -51,7 +54,29 @@ public class UserSystemController {
List<Users> useral2 = usersService.getAllList();
logger.info(">>> 第二遍的全部用户:"+useral2);
String username ="";
//获得session对象
HttpSession session = request.getSession();
//取出session域中所有属性名
Enumeration attributeNames = session.getAttributeNames();
while (attributeNames.hasMoreElements()) {
System.out.println(attributeNames.nextElement());
}
//SPRING_SECURITY_CONTEXT
Object spring_security_context = session.getAttribute("SPRING_SECURITY_CONTEXT");
System.out.println(spring_security_context);
SecurityContext securityContext = (SecurityContext) spring_security_context;
if(securityContext!=null){
//获得认证信息
Authentication authentication = securityContext.getAuthentication();
//获得用户详情
Object principal = authentication.getPrincipal();
User user = (User) principal;
username = user.getUsername();
System.out.println(username);
}
//分页获取主题帖子
// List<Discussions> allDiscussions = discussionsService.getAllList();
@@ -63,19 +88,17 @@ public class UserSystemController {
//获取主题帖子的分页数据
List<String> pageNumList = getPageNumList(allDiscussionsPage.getTotalPages());
//获取所有标签(以后尝试去缓存中取)
List<Tags> allTags = tagsService.getAllList();
logger.info("全部标签==>{}",allTags);
HttpSession session=request.getSession();
System.out.println(userall.toString());
map.put("data", "Jiscuss 用户");
map.put("allDiscussions", allDiscussions);
map.put("pageDiscussions", pageNumList);
map.put("allTags", allTags);
map.put("username", session.getAttribute("username"));
map.put("username", username);
return "index";
}
@@ -99,25 +122,41 @@ public class UserSystemController {
//登录
@PostMapping(value = "/login")
@ResponseBody
public String login(@RequestParam("username") String username, @RequestParam("password") String password,
HttpSession session) {
JSONObject resultobj = new JSONObject();
Users user = usersService.checkByUsernameAndPassword(username, password);
if (user!=null) {
//用户名和密码完成校验
session.setAttribute("username", username); //缓存session
session.setAttribute("userid", user.getId()); //缓存session
resultobj.put("username", username);
resultobj.put("msg", "登录成功");
resultobj.put("flag", true);
} else {
//用户名和密码未完成校验
resultobj.put("msg", "用户名或密码错误");
resultobj.put("flag", false);
// @PostMapping(value = "/login")
// @ResponseBody
// public String login(@RequestParam("username") String username, @RequestParam("password") String password,
// HttpSession session) {
// JSONObject resultobj = new JSONObject();
// Users user = usersService.checkByUsernameAndPassword(username, password);
// if (user!=null) {
// //用户名和密码完成校验
// session.setAttribute("username", username); //缓存session
// session.setAttribute("userid", user.getId()); //缓存session
// resultobj.put("username", username);
// resultobj.put("msg", "登录成功");
// resultobj.put("flag", true);
// } else {
// //用户名和密码未完成校验
// resultobj.put("msg", "用户名或密码错误");
// resultobj.put("flag", false);
// }
// return resultobj.toString();
// }
//登录页
@GetMapping("/login")
public String login(@RequestParam(value = "error", required = false) String error,
@RequestParam(value = "logout", required = false) String logout,Map<String, Object> map) {
if (error != null) {
map.put("msg", "您输入的用户名密码错误!");
return "login";
}
return resultobj.toString();
if (logout != null) {
map.put("msg", "退出成功!");
return "login";
}
return "login";
}
//退出
@@ -3,7 +3,9 @@ package com.yaoyuan.jiscuss.entity;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
@@ -16,11 +18,13 @@ import javax.persistence.Table;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
@Data
@Entity
@Table(name="users")
public class Users implements Serializable {
public class Users implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@@ -65,7 +69,5 @@ public class Users implements Serializable {
@Column(name="level")
private Integer level;
}
@@ -0,0 +1,64 @@
package com.yaoyuan.jiscuss.handler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 处理无权请求
* @author charlie
*
*/
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
private Logger log = LoggerFactory.getLogger(CustomAccessDeniedHandler.class);
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
boolean isAjax = ControllerTools.isAjaxRequest(request);
System.out.println("CustomAccessDeniedHandler handle");
if (!response.isCommitted()) {
if (isAjax) {
String msg = accessDeniedException.getMessage();
log.info("accessDeniedException.message:" + msg);
String accessDenyMsg = "{\"code\":\"403\",\"msg\":\"没有权限\"}";
ControllerTools.print(response, accessDenyMsg);
} else {
request.setAttribute(WebAttributes.ACCESS_DENIED_403, accessDeniedException);
response.setStatus(HttpStatus.FORBIDDEN.value());
RequestDispatcher dispatcher = request.getRequestDispatcher("/403");
dispatcher.forward(request, response);
}
}
}
public static class ControllerTools {
public static boolean isAjaxRequest(HttpServletRequest request) {
return "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
}
public static void print(HttpServletResponse response, String msg) throws IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter writer = response.getWriter();
writer.write(msg);
writer.flush();
writer.close();
}
}
}
@@ -0,0 +1,38 @@
package com.yaoyuan.jiscuss.handler;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* RBAC数据模型控制权限
* @author charlie
*
*/
@Component("rbacPermission")
public class RbacPermission{
private AntPathMatcher antPathMatcher = new AntPathMatcher();
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
Object principal = authentication.getPrincipal();
boolean hasPermission = false;
hasPermission = true;
// if (principal instanceof UserEntity) {
// // 读取用户所拥有的权限菜单
// List<Menu> menus = ((UserEntity) principal).getRoleMenus();
// System.out.println(menus.size());
// for (Menu menu : menus) {
// if (antPathMatcher.match(menu.getMenuUrl(), request.getRequestURI())) {
// hasPermission = true;
// break;
// }
// }
// }
return hasPermission;
}
}
@@ -0,0 +1,59 @@
package com.yaoyuan.jiscuss.service.impl;
import com.yaoyuan.jiscuss.entity.Users;
import com.yaoyuan.jiscuss.service.IUsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author yaoyuan2.chu
* @Title:
* @Package com.yaoyuan.jiscuss.service.impl
* @Description:
* @date 2020/7/15 16:34
*/
@Component
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
private IUsersService userInfoService;
/**
* 需新建配置类注册一个指定的加密方式Bean,或在下一步Security配置类中注册指定
*/
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 通过用户名从数据库获取用户信息
Users userInfo = userInfoService.getByUsername(username);
if (userInfo == null) {
throw new UsernameNotFoundException("用户不存在");
}
// 得到用户角色
String role = "admin";
// 角色集合
List<GrantedAuthority> authorities = new ArrayList<>();
// 角色必须以`ROLE_`开头,数据库中没有,则在这里加
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
return new User(
userInfo.getUsername(),
// 因为数据库是明文,所以这里需加密密码
passwordEncoder.encode(userInfo.getPassword()),
authorities
);
}
}