Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
多的就不做介绍了,这个框架大家应该都很明白,直接步入正题吧!
此篇只写了JWT怎么和Security怎么整合在一起的流程作为笔记。想了解JWT的可去我的博客JWT 这篇有细致讲解。
首先创建对应数据库:
user 存放用户
role存放所有权限
user_role 存放用户和权限的关系
menu 存放动态地址
menu_role存放动态地址和权限之间的关系
org.springframework.boot
spring-boot-starter-security
io.jsonwebtoken
jjwt
0.6.0
com.baomidou
mybatis-plus-boot-starter
2.3
mysql
mysql-connector-java
runtime
mysql
mysql-connector-java
8.0.20
com.alibaba
druid
1.1.6
org.projectlombok
lombok
true
com.google.code.gson
gson
2.8.6
com.alibaba
fastjson
1.2.54
server.port=8080
#mysql
spring.datasource.url=jdbc:mysql://192.168.2.113:3306/securitytest?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type =com.alibaba.druid.pool.DruidDataSource
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#mybatis-plus
mybatis-plus.mapper-locations=classpath:Mapper/*.xml
mybatis-plus.type-aliases-package=com.bxc.securitytest.Entity
mybatis-plus.configuration.map-underscore-to-camel-case: true
@TableName(value = "user") //表名
public class User implements UserDetails {
private int id;
private String username;
private String password;
private Boolean enabled;
private Boolean locked;
@TableField(exist = false)
private List roles;
@Override
public Collection extends GrantedAuthority> getAuthorities() {
List authorities = new ArrayList<>();
for (Role role : roles) {
System.out.println("登录权限:"+role.getRole());
authorities.add(new SimpleGrantedAuthority(role.getRole()));
}
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return !locked;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
//省略getter/setter
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
// public Boolean getEnabled() {
// return enabled;
// }
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
public List getRoles() {
return roles;
}
public void setRoles(List roles) {
this.roles = roles;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", enabled=" + enabled +
", locked=" + locked +
", roles=" + roles +
'}';
}
}
@Mapper
@Component
public interface UserMapper extends BaseMapper {
@Select("select * from user where username = #{username}")
User findUserFromUsername(String username);
@Insert("insert into user(username,password,enabled,locked) value(#{username},#{password},#{enabled},#{locked})")
@Options(useGeneratedKeys = true,keyProperty = "id",keyColumn = "id")
int addUser(User user);
}
@Mapper
@Component
public interface RoleMapper extends BaseMapper {
@Select("select a.* from role a,user_role b where a.id = b.roleid and b.userid = #{id}")
List findRoleFromUserId(int id);
@Select("select id from role where role = #{rolename}")
int findRoleIdFromName(String rolename);
@Insert("insert into user_role(userid,roleid) value(#{userid},#{roleid})")
int insertUserRole(@Param("userid") int userid, @Param("roleid") int roleid);
}
@Mapper
@Component
public interface MenuMapper {
List
@Service
public class UserService implements UserDetailsService {
@Autowired
UserMapper userMapper;
@Autowired
RoleMapper roleMapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userMapper.findUserFromUsername(s);
if (user == null) {
throw new UsernameNotFoundException("账户不存在!");
}
user.setRoles(roleMapper.findRoleFromUserId(user.getId()));
System.out.println(user);
return user;
}
}
@Service
@Slf4j
public class RoleService {
@Autowired
UserMapper userMapper;
@Autowired
RoleMapper roleMapper;
@Autowired
MenuMapper menuMapper;
public boolean AddUser(String username, String password,String role) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(10);
String encodePasswod = encoder.encode(password);
return saveToDb(username, encodePasswod,role);
}
@Transactional(propagation = Propagation.REQUIRED)
public boolean saveToDb(String username, String encodePasswod,String role) {
User user = new User();
user.setUsername(username);
user.setPassword(encodePasswod);
user.setEnabled(true);
user.setLocked(false);
log.info(user.toString());
System.out.println(user.toString());
int count = userMapper.addUser(user);
if (count > 0){
System.out.println(user.toString());
int roleid = roleMapper.findRoleIdFromName(role);
System.out.println(roleid);
int c = roleMapper.insertUserRole(user.getId(),roleid);
if (c > 0){
return true;
}
}
return false;
}
public List
public class LoginAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@SneakyThrows
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
response.setContentType("text/json;charset=utf-8");
if(request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE) ||request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)){
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(request.getInputStream(),"utf-8"));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
JSONObject json= JSONObject.parseObject(sb.toString());
System.out.println(json.toString());
String username = json.getString("username");
String password = json.getString("password");
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
this.setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
} catch (IOException e) {
e.printStackTrace();
response.getWriter().write(JSON.toJSONString(ResSuccessTemplate.builder().code(400).message("参数错误!").build()));
}
} else {
return super.attemptAuthentication(request, response);
}
response.getWriter().write(JSON.toJSONString(ResSuccessTemplate.builder().code(400).message("参数错误!").build()));
return null;
}
}
@Component
public class AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Autowired
JWTUtil jwtUtil;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
User user = (User)authentication.getPrincipal();
String username = user.getUsername();
List authorities = (List) user.getAuthorities();
List list = new ArrayList<>();
String role = "";
for(GrantedAuthority g : authorities){
list.add(g.getAuthority());
role = g.getAuthority();
}
String token = jwtUtil.CreateToken(user.getId()+"",username,role);
response.setContentType("text/json;charset=utf-8");
Map map = new HashMap<>();
map.put("username",username);
map.put("role",role);
map.put("token",token);
response.getWriter().write(JSON.toJSONString(ResSuccessTemplate.builder().data(map).build()));
}
}
@Component
public class AuthenticationFailHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
response.setContentType("text/json;charset=utf-8");
if (e instanceof UsernameNotFoundException || e instanceof BadCredentialsException) {
response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(400).message("用户名或密码错误!").build()));
} else if (e instanceof DisabledException) {
response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(400).message("账户被禁用,请联系管理员!").build()));
} else {
response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(400).message("用户名或密码错误!").build()));
}
}
}
@Component
public class AuthenticationAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException)
throws IOException, ServletException {
response.setContentType("text/json;charset=utf-8");
response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(403).message("权限不足!").build()));
}
}
@Slf4j
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {
@Autowired
JWTUtil jwtUtil;
private Integer tokenExpireTime;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager, Integer tokenExpireTime) {
super(authenticationManager);
this.tokenExpireTime = tokenExpireTime;
}
public JWTAuthenticationFilter(AuthenticationManager authenticationManager, AuthenticationEntryPoint authenticationEntryPoint) {
super(authenticationManager, authenticationEntryPoint);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String token = request.getHeader("token");
if (jwtUtil == null){
jwtUtil = new JWTUtil();
}
boolean isold = jwtUtil.VerityToken(token);
response.setContentType("text/json;charset=utf-8");
if (!isold) {
response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(401).message("登录失效!").build()));
return;
}
String username = jwtUtil.getUserName(token);
if (StringUtils.isEmpty(username)){
response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(401).message("登录失效!").build()));
return;
}
String role = jwtUtil.getUserRoles(token);
List authorities = new ArrayList<>();
if(StringUtils.isEmpty(role)){
response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(403).message("权限不足!").build()));
return;
}
authorities.add(new SimpleGrantedAuthority(role));
User principal = new User();
principal.setUsername(username);
try {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(principal, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
String userid = jwtUtil.getUserid(token);
request.setAttribute("userid",userid);
request.setAttribute("username",username);
request.setAttribute("role",role);
System.out.println("过滤权限:"+role);
chain.doFilter(request, response);
}catch (Exception e){
e.printStackTrace();
response.getWriter().write(JSON.toJSONString(ResFailTemplate.builder().code(401).message("登录失效!").build()));
}
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserService userService;
@Autowired
RoleService roleService;
@Autowired
AuthenticationSuccessHandler successHandler;
@Autowired
AuthenticationFailHandler failHandler;
@Autowired
AuthenticationAccessDeniedHandler deniedHandler;
@Bean
RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
String hierarchy = "ROLE_admin > ROLE_user > ROLE_common";
roleHierarchy.setHierarchy(hierarchy);
return roleHierarchy;
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
@Bean
LoginAuthenticationFilter customAuthenticationFilter() throws Exception {
LoginAuthenticationFilter filter = new LoginAuthenticationFilter();
filter.setAuthenticationSuccessHandler(successHandler);
filter.setAuthenticationFailureHandler(failHandler);
filter.setFilterProcessesUrl("/login");
//这句很关键,重用WebSecurityConfigurerAdapter配置的AuthenticationManager,不然要自己组装AuthenticationManager
filter.setAuthenticationManager(authenticationManagerBean());
return filter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry authorizeRequests = http
.authorizeRequests();
List
@RestController
public class TestController {
@Autowired
UserService userService;
@Autowired
RoleService roleService;
@GetMapping("/Admin/AdminTest")
public String AdminTest(){
return "Admin - Success";
}
@GetMapping("/User/UserTest")
public String UserTest(){
return "User - Success";
}
@GetMapping("/Common/CommonTest")
public String CommonTest(HttpServletRequest request){
String userid = (String) request.getAttribute("userid");
String username = (String) request.getAttribute("username");
String role = (String) request.getAttribute("role");
return "Common - Success"+"userid="+userid+", username="+username+",role="+role;
}
}