1.建表,五张表,如下:
1.1.用户表
CREATE TABLE `t_sys_user` (
`user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`user_name` varchar(30) NOT NULL COMMENT '用户名',
`user_password` varchar(128) NOT NULL COMMENT '用户密码',
`salt` varchar(64) DEFAULT NULL COMMENT '加密盐',
`user_phone` varchar(20) DEFAULT NULL COMMENT '手机号',
`user_emai` varchar(20) DEFAULT NULL COMMENT '邮箱',
`user_title` varchar(20) DEFAULT NULL COMMENT '职称',
`creater_id` bigint(20) DEFAULT NULL COMMENT '创建人ID',
`creater_name` varchar(30) DEFAULT NULL COMMENT '创建人名称',
`creater_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater_id` bigint(20) DEFAULT NULL COMMENT '更新人ID',
`updater_name` varchar(30) DEFAULT NULL COMMENT '更新人名称',
`updater_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
`role_ids` varchar(200) DEFAULT NULL,
`role_names` varchar(300) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

1.2.用户角色表
CREATE TABLE `t_sys_user_role` (
`user_role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户角色ID',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`role_id` bigint(20) NOT NULL COMMENT '角色ID',
PRIMARY KEY (`user_role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8;

1.3.角色表
CREATE TABLE `t_sys_role` (
`role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID',
`role_name` varchar(100) NOT NULL COMMENT '角色名称',
`role_code` varchar(100) NOT NULL COMMENT '角色编码',
`creater_id` bigint(20) DEFAULT NULL COMMENT '创建人ID',
`creater_name` varchar(30) DEFAULT NULL COMMENT '创建人名称',
`creater_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater_id` bigint(20) DEFAULT NULL COMMENT '更新人ID',
`updater_name` varchar(30) DEFAULT NULL COMMENT '更新人名称',
`updater_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
`permission_ids` varchar(200) DEFAULT NULL,
`permission_names` varchar(300) DEFAULT NULL,
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

1.4.角色权限表
CREATE TABLE `t_sys_role_permission` (
`role_permission_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色权限ID',
`role_id` bigint(20) NOT NULL COMMENT '角色ID',
`permission_id` bigint(20) NOT NULL COMMENT '权限ID',
PRIMARY KEY (`role_permission_id`)
) ENGINE=InnoDB AUTO_INCREMENT=78 DEFAULT CHARSET=utf8;

1.5.权限表

CREATE TABLE `t_sys_permission` (
`permission_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '权限ID',
`permission_name` varchar(100) NOT NULL COMMENT '权限名称',
`permission_code` varchar(100) NOT NULL COMMENT '权限编码',
`creater_id` bigint(20) DEFAULT NULL COMMENT '创建人ID',
`creater_name` varchar(30) DEFAULT NULL COMMENT '创建人名称',
`creater_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater_id` bigint(20) DEFAULT NULL COMMENT '更新人ID',
`updater_name` varchar(30) DEFAULT NULL COMMENT '更新人名称',
`updater_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`permission_id`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;

2.pom.xml引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

3.编码步骤:
3.1.在用户实体类中实现UserDetails接口的方法

package com.lz.hehuorenservice.system.entity;

import com.lz.hehuorenservice.common.entity.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails; import java.util.*; /** Create by hyhweb on 2021/6/6 16:24 */
public class User extends BaseEntity implements UserDetails { /** 用户主键ID */
@ApiModelProperty(value = "用户主键ID")
private Long userId;
/** 用户名 */
@ApiModelProperty(value = "用户名")
private String userName;
/** 用户密码 */
@ApiModelProperty(value = "用户密码")
private String userPassword; @ApiModelProperty(value = "")
private String salt;
/** 手机号 */
@ApiModelProperty(value = "手机号")
private String userPhone;
/** 邮箱 */
@ApiModelProperty(value = "邮箱")
private String userEmai;
/** 职称 */
@ApiModelProperty(value = "职称")
private String userTitle; @ApiModelProperty(value = "角色ID")
private String roleIds; @ApiModelProperty(value = "角色名称")
private String roleNames;
/** 创建人ID */
@ApiModelProperty(value = "创建人ID")
private Long createrId;
/** 创建人名称 */
@ApiModelProperty(value = "创建人名称")
private String createrName;
/** 创建时间 */
@ApiModelProperty(value = "创建时间")
private Date createrTime;
/** 更新人ID */
@ApiModelProperty(value = "更新人ID")
private Long updaterId;
/** 更新人名称 */
@ApiModelProperty(value = "更新人名称")
private String updaterName;
/** 更新时间 */
@ApiModelProperty(value = "更新时间")
private Date updaterTime; private Set<String> permissions; @Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
/*
//绑定角色的授权方法
if(roles !=null){
for (Role sysRole : roles) {
authorities.add(new SimpleGrantedAuthority(sysRole.getRoleCode()));
}
}*/ // 绑定权限的授权方法
if (permissions != null) {
for (String permission : permissions) {
authorities.add(new SimpleGrantedAuthority(permission));
}
} return authorities;
} @Override
public String getPassword() {
return userPassword;
} @Override
public String getUsername() {
return userName;
} @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 Long getUserId() {
return userId;
} public void setUserId(Long userId) {
this.userId = userId;
} public String getUserName() {
return userName;
} public void setUserName(String userName) {
this.userName = userName;
} public String getUserPassword() {
return userPassword;
} public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
} public String getSalt() {
return salt;
} public void setSalt(String salt) {
this.salt = salt;
} public String getUserPhone() {
return userPhone;
} public void setUserPhone(String userPhone) {
this.userPhone = userPhone;
} public String getUserEmai() {
return userEmai;
} public void setUserEmai(String userEmai) {
this.userEmai = userEmai;
} public String getUserTitle() {
return userTitle;
} public void setUserTitle(String userTitle) {
this.userTitle = userTitle;
} public String getRoleIds() {
return roleIds;
} public void setRoleIds(String roleIds) {
this.roleIds = roleIds;
} public String getRoleNames() {
return roleNames;
} public void setRoleNames(String roleNames) {
this.roleNames = roleNames;
} public Long getCreaterId() {
return createrId;
} public void setCreaterId(Long createrId) {
this.createrId = createrId;
} public String getCreaterName() {
return createrName;
} public void setCreaterName(String createrName) {
this.createrName = createrName;
} public Date getCreaterTime() {
return createrTime;
} public void setCreaterTime(Date createrTime) {
this.createrTime = createrTime;
} public Long getUpdaterId() {
return updaterId;
} public void setUpdaterId(Long updaterId) {
this.updaterId = updaterId;
} public String getUpdaterName() {
return updaterName;
} public void setUpdaterName(String updaterName) {
this.updaterName = updaterName;
} public Date getUpdaterTime() {
return updaterTime;
} public void setUpdaterTime(Date updaterTime) {
this.updaterTime = updaterTime;
} public Set<String> getPermissions() {
return permissions;
} public void setPermissions(Set<String> permissions) {
this.permissions = permissions;
}
}

3.2.在用户的服务实现类中,实现UserDetailsService接口的loadUserByUsername方法,返回用户的所有信息。

package com.lz.hehuorenservice.system.service.impl;

import com.lz.hehuorenservice.common.service.impl.BaseServiceImpl;
import com.lz.hehuorenservice.system.dao.UserDao;
import com.lz.hehuorenservice.system.entity.User;
import com.lz.hehuorenservice.system.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
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.Set; /** Create by hyhweb on 2021/6/6 16:28 */
@Service
public class UserServiceImpl extends BaseServiceImpl<User, Long>
implements UserService, UserDetailsService {
@Autowired UserDao userDao; @Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
User user = userDao.getUserByName(userName);
if (user == null) {
throw new UsernameNotFoundException("账户不存在");
}
Set<String> permissions = userDao.getPermissionByUserId(user.getUserId());
user.setPermissions(permissions);
return user;
}
}

3.3.编写配置类,重写WebSecurityConfigurerAdapter类的三个configure方法,也就是重新配置三个对象AuthenticationManagerBuilder,HttpSecurity,WebSecurity。

package com.lz.hehuorenservice.common.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lz.hehuorenservice.common.bean.CustomAccessDeniedHandler;
import com.lz.hehuorenservice.common.bean.CustomAuthenticationEntryPoint;
import com.lz.hehuorenservice.common.filter.CustomAuthenticationFilter;
import com.lz.hehuorenservice.system.entity.User;
import com.lz.hehuorenservice.system.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.*;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.cors.CorsUtils; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map; /** Create by hyhweb on 2021/6/7 8:26 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired UserServiceImpl userService; // 这个必须是接口的实现类,不能是接口 @Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10);
// return NoOpPasswordEncoder.getInstance();
} /* @Bean
RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
// String hierarchy = "ROLE_dba> ROLE_admin \n ROLE_admin > ROLE_user";
String hierarchy = "ROLE_admin > ROLE_user";
roleHierarchy.setHierarchy(hierarchy);
return roleHierarchy;
}*/ @Bean
CustomAuthenticationFilter customAuthenticationFilter() throws Exception {
CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
filter.setAuthenticationSuccessHandler(
new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(
HttpServletRequest req, HttpServletResponse resp, Authentication auth)
throws IOException, ServletException {
Object principal = auth.getPrincipal();
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
resp.setStatus(200);
Map<String, Object> map = new HashMap<>();
map.put("code", "1");
map.put("success", true);
map.put("message", "登录成功");
User user = (User) principal;
user.setUserPassword(null);
map.put("data", user);
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
/* resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String,Object> map = new HashMap<String,Object>();
map.put("message", "登录成功");
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();*/ }
});
filter.setAuthenticationFailureHandler(
new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(
HttpServletRequest req, HttpServletResponse resp, AuthenticationException e)
throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
resp.setStatus(401);
Map<String, Object> map = new HashMap<>();
map.put("status", 401);
if (e instanceof LockedException) {
map.put("msg", "账号被锁定,登录失败");
} else if (e instanceof BadCredentialsException) {
map.put("msg", "账号或密码输入错误,请重新登录");
} else if (e instanceof DisabledException) {
map.put("msg", "账号被禁用,登录失败");
} else if (e instanceof AccountExpiredException) {
map.put("msg", "账号过期,登录失败");
} else if (e instanceof CredentialsExpiredException) {
map.put("msg", "密码过期,登录失败");
} else {
map.put("msg", "登录失败");
}
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
/*resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
Map<String,Object> map = new HashMap<String,Object>();
map.put("message", "登录失败");
out.write(new ObjectMapper().writeValueAsString(map));
out.flush();
out.close();*/
}
});
filter.setAuthenticationManager(authenticationManagerBean());
return filter;
} @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
} @Bean
public AccessDeniedHandler getAccessDeniedHandler() {
return new CustomAccessDeniedHandler();
} @Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/sessionInvalid", "/register", "/app/**", "/login_page")
.antMatchers("/index.html", "/static/**", "/favicon.ico")
.antMatchers(
"/swagger-ui/**",
"/swagger/**",
"/doc.html",
"/swagger-resources/**",
"/images/**",
"/webjars/**",
"/v3/api-docs",
"/configuration/ui",
"/configuration/security");
} @Override
protected void configure(HttpSecurity http) throws Exception {
http.cors() // 开启跨域
.and() // 获取一个安全编译器
.authorizeRequests() // 授权请求
.requestMatchers(CorsUtils::isPreFlightRequest)
.permitAll() // 跨域的请求开放所有权限
.anyRequest() // 所有请求
.authenticated() // 所有请求都需要认证
.and()
.sessionManagement()
.invalidSessionUrl("/session/invalid")
.and()
// 获取一个安全编译器
.formLogin()
// 表单登录配置
.loginPage("/login_page")
// 登录页面访问地址
.loginProcessingUrl("/login")
// 配置登录接口地址
.usernameParameter("userName")
// 配置登录的账号字段
.passwordParameter("userPassWord")
// 配置登录密码字段
.and()
// 获取一个安全编译器
.logout()
// 退出登录配置
.logoutUrl("/logout")
// 设置退出登录的接口地址
.clearAuthentication(true)
// 清除所有认证信息
.invalidateHttpSession(true)
// 让session失效
.addLogoutHandler(
new LogoutHandler() {
// 退出登录时的处理器
@Override
public void logout(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Authentication authentication) {}
})
.logoutSuccessHandler(
new LogoutSuccessHandler() {
// 退出成功后的处理器
@Override
public void onLogoutSuccess(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Authentication authentication)
throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
Map<String, Object> map = new HashMap<>();
map.put("message", "退出成功");
map.put("code", "1");
map.put("success", true);
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
})
.permitAll() // 设置退出登录的所有权限
.and() // 获取一个安全编译器
.csrf()
.disable() // 关闭csrf跨站点请求伪造
.exceptionHandling()
.authenticationEntryPoint(new CustomAuthenticationEntryPoint());
// 自定义认证的入口异常处理方法
http.addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
// 重写用户名密码的过滤器,实现前后端分离获取登录的用户名,密码信息
http.exceptionHandling().accessDeniedHandler(getAccessDeniedHandler());
// 没有权限访问的处理器
}
}

3.3.1CustomAccessDeniedHandler自定义没权限方法的处理器

package com.lz.hehuorenservice.common.bean;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map; /** Create by hyhweb on 2021/6/7 11:50 */
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AccessDeniedException e)
throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
Map map = new HashMap<>();
map.put("message", "权限不足,请联系管理员开通权限");
map.put("code", 0);
map.put("status", 403);
map.put("success", false);
String result = new ObjectMapper().writeValueAsString(map);
out.write(result);
out.flush();
out.close();
}
} 3.3.2CustomAuthenticationEntryPoint自定义认证的入口
package com.lz.hehuorenservice.common.bean; import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map; /** Create by hyhweb on 2021/6/7 11:42 */
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e)
throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
Map map = new HashMap<>();
map.put("message", "还没登录,请重新登录");
map.put("code", 302);
String result = new ObjectMapper().writeValueAsString(map);
out.write(result);
out.flush();
out.close();
}
}

3.3.3.CustomAuthenticationFilter自定义

package com.lz.hehuorenservice.common.filter;

import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream; /** Create by hyhweb on 2021/6/7 12:07 */
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(
HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE)
|| request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
UsernamePasswordAuthenticationToken authRequest = null;
try (InputStream is = request.getInputStream()) {
ObjectMapper mapper = new ObjectMapper();
Map<String, String> authenticationBean = mapper.readValue(is, Map.class);
authRequest = new UsernamePasswordAuthenticationToken(
authenticationBean.get("userName"), authenticationBean.get("userPassWord"));
/* authRequest =
new UsernamePasswordAuthenticationToken(
request.getParameter("userName"), request.getParameter("userPassWord"));*/
} catch (IOException e) {
e.printStackTrace();
authRequest = new UsernamePasswordAuthenticationToken("", "");
} finally {
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
} else {
return super.attemptAuthentication(request, response);
}
}
}

4.controller层使用权限注释@PreAuthorize实现权限控制

@RestController
@RequestMapping("/user")
@Api(tags = "用户信息")
public class UserController{
@Autowired private UserService userService; @ApiOperation(value = "删除单个对象", notes = "删除单个对象接口")
@GetMapping("/delete/{id}")
@PreAuthorize("hasAuthority('delete')")
public ApiResult deleteById(@PathVariable long id) {
return userService.deleteById(id);
}
}

附加说明:
Spring Security的表达式对象的基类:
org.springframework.security.access.expression.SecurityExpressionRoot
在controller的方法中使用注释,如下:
@PreAuthorize(“表达式(‘权限值’)”)

@PreAuthorize("hasAuthority('zixunguanli-xinzeng')")
public ApiResult add(@RequestBody String json) {
return infoService.add(JSON.parseObject(json, InfoReq.class));
}

表达式如下:

boolean hasAuthority(String var1);

boolean hasAnyAuthority(String... var1);

boolean hasRole(String var1);

boolean hasAnyRole(String... var1);

boolean permitAll();

boolean denyAll();

boolean isAnonymous();

boolean isAuthenticated();

boolean isRememberMe();

boolean isFullyAuthenticated();

boolean hasPermission(Object var1, Object var2);

boolean hasPermission(Object var1, String var2, Object var3);

Spring Security的重构获取用户名和密码的方式,实现前后端分离的json格式,如下:
重构org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter的attemptAuthentication方法

spring boot集成spring security(jwt+redis有完整源码)

一、Spring Security官方解释
Spring Security是一个强大的和高度可定制的身份验证和访问控制框架。它是保证基于spring的应用程序安全的实际标准。Spring Security是一个框架,着重于为Java应用程序提供身份验证和授权。春天像所有项目,Spring Security的真正力量是很容易找到的它可以扩展以满足定制需求。

本项目使用jwt当作token,使用redis存储token,登录信息不依赖于单个项目,集中存储到redis内存型数据库中。

二、spring boot集成步骤(完整项目地址:https://gitee.com/fds520/spring-security-demo)
1. 项目结构

2.核心代码

主配置类SpringSecurityConfig
package com.fds.system.config;

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; /**
* spring security 主配置类
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; @Autowired
private SecurityProperties securityProperties; @Override
protected void configure(HttpSecurity http) throws Exception {
// 禁用 csrf 拦截
http.csrf().disable()
.sessionManagement()
// 关闭session管理,使用token机制处理
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// 未登录返回 JSON 格式的数据
.httpBasic().authenticationEntryPoint((httpServletRequest, httpServletResponse, e) -> {
httpServletRequest.setCharacterEncoding("utf-8");
httpServletResponse.setHeader("Content-type", "application/json;charset=UTF-8");
httpServletResponse.getWriter().write(JSON.toJSONString("未登录"));
})
.and()
// 无权访问 JSON 格式的数据
.exceptionHandling().accessDeniedHandler((httpServletRequest, httpServletResponse, e) -> {
httpServletResponse.setCharacterEncoding("utf-8");
httpServletResponse.setHeader("Content-type", "application/json;charset=UTF-8");
httpServletResponse.getWriter().write(JSON.toJSONString("没有权限"));
})
.and()
.authorizeRequests()
// 对option不校验
.antMatchers(HttpMethod.OPTIONS).permitAll()
// 设置不校验白名单
.antMatchers(securityProperties.getIgnoreUrl()).permitAll()
.anyRequest().authenticated()
.and()
// 添加自定义请求jwt过滤器
.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
} @Override
public void configure(WebSecurity web) {
// 设置拦截忽略文件夹,可以对静态资源放行
web.ignoring().antMatchers("/images/**");
}
}
登录service
/**
* 获取数据库用户
*
* @param username 用户名
* @return
* @throws UsernameNotFoundException
*/
public String login(String username, String password) {
// 模拟从数据库 获取登录用户
LoginUser loginUser = new LoginUser("fds", "123");
loginUser.setId(123L);
loginUser.setType("people");
Set authoritiesSet = new HashSet();
// 模拟从数据库中获取用户权限
authoritiesSet.add("test:add");
authoritiesSet.add("test:list");
authoritiesSet.add("ddd:list");
loginUser.setCustomAuthorities(authoritiesSet);
String token = JwtTokenUtil.generateToken(loginUser);
redisUtil.set(token, JSONObject.toJSONString(loginUser), securityProperties.getExpirationMilliSeconds());
return token;
}
token过滤器
package com.fds.system.config;

import com.alibaba.fastjson.JSONObject;
import com.fds.system.model.LoginUser;
import com.fds.system.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author: fds
* @description: jwt-token过滤器
*/
@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { @Autowired
private SecurityProperties securityProperties; @Autowired
private RedisUtil redisUtil; @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authToken = request.getHeader("Authorization");
response.setCharacterEncoding("utf-8");
if (StringUtils.isEmpty(authToken)) {
// 用户未登录
filterChain.doFilter(request, response);
return;
}
// 获取redis中的token信息
if (!redisUtil.hasKey(authToken)) {
// 用户未登录
filterChain.doFilter(request, response);
return;
} Object data = redisUtil.get(authToken);
if (null == data) {
// 用户未登录
filterChain.doFilter(request, response);
return;
} // 获取缓存中的信息(根据自己的业务进行拓展)
LoginUser loginUser = JSONObject.parseObject(data.toString(), LoginUser.class);
// 设置权限
loginUser.setSystemAuthorities();
// 从tokenInfo中取出用户信息
// 更新token过期时间
redisUtil.setKeyExpire(authToken, securityProperties.getExpirationMilliSeconds());
// 将信息交给security
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
}
}

  

												

springboot整合security实现权限控制的更多相关文章

  1. SpringBoot整合Shiro实现权限控制,验证码

    本文介绍 SpringBoot 整合 shiro,相对于 Spring Security 而言,shiro 更加简单,没有那么复杂. 目前我的需求是一个博客系统,有用户和管理员两种角色.一个用户可能有 ...

  2. SpringBoot整合Shiro实现权限控制

    目录 1.SpringBoot整合Shiro 1.1.shiro简介 1.2.代码的具体实现 1.2.1.Maven的配置 1.2.2.整合需要实现的类 1.2.3.项目结构 1.2.4.ShiroC ...

  3. request.getRemoteUser() Spring Security做权限控制后

    一. request.getRemoteUser();//获取当前缓存的用户,比如Spring Security做权限控制后就会将用户登录名缓存到这里 request.getRemoteAddr(); ...

  4. springboot整合security实现基于url的权限控制

    权限控制基本上是任何一个web项目都要有的,为此spring为我们提供security模块来实现权限控制,网上找了很多资料,但是提供的demo代码都不能完全满足我的需求,因此自己整理了一版. 在上代码 ...

  5. springboot集成shiro 实现权限控制(转)

    shiro apache shiro 是一个轻量级的身份验证与授权框架,与spring security 相比较,简单易用,灵活性高,springboot本身是提供了对security的支持,毕竟是自 ...

  6. springboot整合shiro进行权限管理

    背景:springboot2.1,shiro1.4:由于目前的小项目没做登录,但是客户又需要加上权限,因此楼主就想到了shiro(这是单独的项目,需要集成后台管理系统) shiro简介 Apache ...

  7. SpringBoot + Security实现权限控制

    网上找了好几个,因为各种原因不太行,下面这个亲测可行 参考:https://blog.csdn.net/u012702547/article/details/54319508 基于SpringBoot ...

  8. SpringBoot集成Shiro实现权限控制

    Shiro简介 Apache Shiro是一个功能强大且易于使用的Java安全框架,用于执行身份验证,授权,加密和会话管理.使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序-从最小的移 ...

  9. SpringBoot整合Apache Shiro权限验证框架

    比较常见的权限框架有两种,一种是Spring Security,另一种是Apache Shiro,两种框架各有优劣,个人感觉Shiro更容易使用,更加灵活,也更符合RABC规则,而且是java官方更推 ...

  10. shiro系列三、ssm框架整合shiro实现权限控制

    shiro权限框架是一个非常优秀的框架,前面的几篇文章对shiro进行了非常详细的介绍和原理分析,那么接下来让我们开始在web项目中使用它(javase也能用shiro): 一.数据库表结构设计 二. ...

随机推荐

  1. js中栈的运用

    JavaScript 中栈的运用 在 JavaScript 中,栈(Stack)是一种非常有用的数据结构,它遵循后进先出(Last In First Out,LIFO)的原则.在本文中,我们将深入探讨 ...

  2. php yield使用

    在循环一个大数组的时候yield非常好用能节省内存. 比如有个大文件需要读取并处理,如果全部读出来太耗费内存,就可以这样做 <?php function getRows($file) { $ha ...

  3. 使用缓存构建更快的 Web 应用程序

    使用 Java 缓存系统缓存频繁查看的数据 使用 Java 技术的 Web 开发人员可以使用缓存实用程序快速提升他们的应用程序的性能.Java 缓存系统(Java Caching System,JCS ...

  4. Integrating JDBC with Hibernate

    One of the powerful things about Hibernate is that you do not typically need to manually write SQL: ...

  5. Python:pygame游戏编程之旅六(游戏中的声音处理)

    一款人性化的游戏中缺少不了声音,比如角色挂时惨叫一声,或PK时武器交锋的声音,还有就是英雄出场时的背景音乐,无不涉及到声音,本节我们就来看一下pygame中如何控制声音,下面是一个例子,但博客上传不了 ...

  6. MySQL底层概述—6.索引原理

    大纲 1.索引原理 2.二叉查找树 3.平衡二叉树(AVL树) 4.红黑树 5.B-Tree 6.B+Tree 7.Hash索引 8.聚簇索引与非聚簇索引 1.索引原理 索引会在数据文件中(ibd文件 ...

  7. springboot 参数注解 注入参数

    什么时注解参数 说明 我们在 使用spring mvc 的时候会使用这样的注解 @ResponseBody 这样,spring mvc 会将 客户端传来的数据,自动构建成 相应类型的对象. 有些情况下 ...

  8. 人工智能大语言模型起源篇,低秩微调(LoRA)

    上一篇: <规模法则(Scaling Law)与参数效率的提高> 序言:您在找工作时会不会经常听到LoRA微调,这项技术的来源就是这里了. (12)Hu.Shen.Wallis.Allen ...

  9. [OS] 计算机资源虚拟化技术

    1 定义:计算机资源虚拟化 服务器虚拟化主要通过软件技术将物理服务器的硬件资源抽象化,创建多个独立的虚拟服务器环境. 2 虚拟化技术方向 以下是一些常见的服务器虚拟化方式和工具: 基于hypervis ...

  10. django视图层与cbv源码分析

    目录 一.视图层之必会三板斧 二.JsonResponse对象 两种序列化数据的方式 方式一:使用json模块 方式二:使用JsonResponse对象 使用JsonResponse对象序列化除字典外 ...