当前位置: 首页 > news >正文

专业电商网站开发百度商家平台

专业电商网站开发,百度商家平台,网站关键字推广,河北搜索引擎推广服务目录 1. 数据库设计 2. 代码设计 登录认证过滤器 认证成功处理器AuthenticationSuccessHandler 认证失败处理器AuthenticationFailureHandler AuthenticationEntryPoint配置 AccessDeniedHandler配置 UserDetailsService配置 Token校验过滤器 登录认证过滤器接口配置…

目录

1. 数据库设计

2. 代码设计

登录认证过滤器

认证成功处理器AuthenticationSuccessHandler

认证失败处理器AuthenticationFailureHandler

AuthenticationEntryPoint配置

AccessDeniedHandler配置

UserDetailsService配置

Token校验过滤器

登录认证过滤器接口配置

Spring Security全局配置

util包

测试结果


在SpringSecurity实现前后端分离登录token认证详解_springsecurity前后端分离登录认证-CSDN博客基础上进行重构,实现前后端分离架构登录认证,基本思想相同,借鉴开源Gitee代码进行改造,具有更好的代码规范。

1. 数据库设计

DROP TABLE IF EXISTS `t_auth`;
CREATE TABLE `t_auth`  (`id` BIGINT(11) NOT NULL AUTO_INCREMENT,`name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '名称',`url` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '路径',`status` INT(1) NULL DEFAULT NULL,`create_time` DATETIME(0) NULL DEFAULT NULL,`update_time` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = COMPACT;-- ----------------------------
-- Records of t_auth
-- ----------------------------
INSERT INTO `t_auth` VALUES (1, '删除用户', '/usr/del', 1, '2021-11-26 17:08:11', '2021-11-26 17:07:52');
INSERT INTO `t_auth` VALUES (2, '新增用户', '/usr/add', 1, '2021-11-26 17:08:13', '2021-11-26 17:08:09');
INSERT INTO `t_auth` VALUES (3, '添加产品', '/product/add', 1, '2021-11-26 17:08:42', '2021-11-26 17:08:29');
INSERT INTO `t_auth` VALUES (4, '下架产品', '/product/del', NULL, NULL, '2021-11-26 17:12:17');
INSERT INTO `t_auth` VALUES (5, '注册', '/user/register', NULL, NULL, '2021-11-26 17:13:32');
INSERT INTO `t_auth` VALUES (6, '注销', '/user/logOff', NULL, NULL, '2021-11-26 17:13:50');-- ----------------------------
-- Table structure for t_role
-- ----------------------------
DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role`  (`id` BIGINT(11) NOT NULL,`name` VARCHAR(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色名称',`status` INT(1) NULL DEFAULT NULL,`create_time` DATETIME(0) NULL DEFAULT NULL,`update_time` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = COMPACT;-- ----------------------------
-- Records of t_role
-- ----------------------------
INSERT INTO `t_role` VALUES (1, 'ROLE_admin', 1, '2021-11-26 17:08:52', '2021-11-26 17:08:51');
INSERT INTO `t_role` VALUES (2, 'ROLE_dba', 1, '2021-11-26 17:09:10', '2021-11-26 17:09:05');
INSERT INTO `t_role` VALUES (3, 'ROLE_vip', 1, '2021-11-26 17:09:32', '2021-11-26 17:09:25');
INSERT INTO `t_role` VALUES (4, 'ROLE_user', 1, '2021-11-26 17:09:45', '2021-11-26 17:09:42');-- ----------------------------
-- Table structure for t_role_auth
-- ----------------------------
DROP TABLE IF EXISTS `t_role_auth`;
CREATE TABLE `t_role_auth`  (`id` BIGINT(20) NOT NULL AUTO_INCREMENT,`role_id` BIGINT(20) NULL DEFAULT NULL,`auth_id` BIGINT(20) NULL DEFAULT NULL,`status` INT(1) NULL DEFAULT NULL,`create_time` DATETIME(0) NULL DEFAULT NULL,`update_time` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = COMPACT;-- ----------------------------
-- Records of t_role_auth
-- ----------------------------
INSERT INTO `t_role_auth` VALUES (1, 1, 3, 1, '2021-11-26 17:11:31', '2021-11-26 17:11:29');
INSERT INTO `t_role_auth` VALUES (2, 1, 4, 1, '2021-11-26 17:11:31', '2021-11-26 17:11:29');
INSERT INTO `t_role_auth` VALUES (3, 4, 5, 1, '2021-11-26 17:14:45', '2021-11-26 17:14:35');
INSERT INTO `t_role_auth` VALUES (4, 4, 6, 1, '2021-11-26 17:14:47', '2021-11-26 17:14:41');-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user`  (`id` BIGINT(11) NOT NULL,`user_id` VARCHAR(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '唯一的userId',`username` VARCHAR(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名',`password` VARCHAR(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码',`name` VARCHAR(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名',`status` INT(1) NULL DEFAULT NULL,`create_time` DATETIME(0) NULL DEFAULT NULL,`update_time` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = COMPACT;-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES (1, '120', 'zhangsan', '123456', '张三', 1, '2021-11-26 17:07:03', '2021-11-26 17:06:53');
INSERT INTO `t_user` VALUES (2, '110', 'lisi', '123456', '李四', 1, '2021-11-26 17:07:36', '2021-11-26 17:07:12');-- ----------------------------
-- Table structure for t_user_role
-- ----------------------------
DROP TABLE IF EXISTS `t_user_role`;
CREATE TABLE `t_user_role`  (`id` BIGINT(20) NOT NULL AUTO_INCREMENT,`user_id` VARCHAR(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户唯一userId',`role_id` BIGINT(20) NULL DEFAULT NULL,`status` INT(1) NULL DEFAULT NULL,`create_time` DATETIME(0) NULL DEFAULT NULL,`update_time` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = COMPACT;-- ----------------------------
-- Records of t_user_role
-- ----------------------------
INSERT INTO `t_user_role` VALUES (1, '120', 1, 1, '2021-11-26 17:10:10', '2021-11-26 17:10:11');
INSERT INTO `t_user_role` VALUES (2, '110', 2, 1, '2021-11-26 17:11:16', '2021-11-26 17:11:13');

2. 代码设计

登录认证过滤器

Spring Security默认的表单登录认证的过滤器是UsernamePasswordAuthenticationFilter,这个过滤器并不适用于前后端分离的架构,因此我们需要自定义一个过滤器。参照UsernamePasswordAuthenticationFilter这个过滤器改造一下。

/*** 登录认证的filter,参照UsernamePasswordAuthenticationFilter,添加到这之前的过滤器*/public class JwtAuthenticationLoginFilter extends AbstractAuthenticationProcessingFilter {/*** 构造方法,调用父类的,设置登录地址/login,请求方式POST*/public JwtAuthenticationLoginFilter() {super(new AntPathRequestMatcher("/login", "POST"));}@Overridepublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {//获取表单提交数据String username = request.getParameter("username");String password = request.getParameter("password");//封装到token中提交UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,password);return getAuthenticationManager().authenticate(authRequest);}
}

认证成功处理器AuthenticationSuccessHandler

上述的过滤器接口一旦认证成功,则会调用AuthenticationSuccessHandler进行处理,因此我们可以自定义一个认证成功处理器进行自己的业务处理,代码如下:

@Component
public class LoginAuthenticationSuccessHandler implements AuthenticationSuccessHandler {@Autowiredprivate JwtUtil jwtUtil;@AutowiredRedisTemplate redisTemplate;@Overridepublic void onAuthenticationSuccess(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Authentication authentication) throws IOException {UserDetails userDetails = (UserDetails) authentication.getPrincipal();SecurityContextHolder.getContext().setAuthentication(authentication);Map<String,String> map=new HashMap<>();map.put("username",userDetails.getUsername());//jwt生成tokenString token = jwtUtil.getToken(map);RedisUser redisUser = RedisUser.builder().username(userDetails.getUsername()).password(userDetails.getPassword()).authorities(userDetails.getAuthorities().stream().map(i->i.getAuthority()).collect(Collectors.toList())).build();//将用户信息保存到redis缓存中redisTemplate.opsForValue().set(userDetails.getUsername(),redisUser,12, TimeUnit.HOURS);ResponseUtils.result(httpServletResponse,new ResultMsg(200,"登录成功!",token));}}

认证失败处理器AuthenticationFailureHandler

同样的,一旦登录失败,比如用户名或者密码错误等等,则会调用AuthenticationFailureHandler进行处理,因此我们需要自定义一个认证失败的处理器,其中根据异常信息返回特定的JSON数据给客户端,代码如下:

@Component
public class LoginAuthenticationFailureHandler implements AuthenticationFailureHandler {/*** 一旦登录失败则会被调用*/@Overridepublic void onAuthenticationFailure(HttpServletRequest httpServletRequest,HttpServletResponse response,AuthenticationException exception) throws IOException {//TODO 根据项目需要返回指定异常提示,这里演示了一个用户名密码错误的异常//BadCredentialsException 这个异常一般是用户名或者密码错误if (exception instanceof BadCredentialsException){ResponseUtils.result(response,new ResultMsg(200,"用户名或密码不正确!",null));}ResponseUtils.result(response,new ResultMsg(200,"登录失败",null));}
}

AuthenticationEntryPoint配置

AuthenticationEntryPoint这个接口当用户未通过认证访问受保护的资源时,将会调用其中的commence()方法进行处理。

@Component
@Slf4j
public class EntryPointUnauthorizedHandler implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {ResponseUtils.result(response,new ResultMsg(403,"认证失败,请重新登录!",null));}
}

AccessDeniedHandler配置

AccessDeniedHandler这处理器当认证成功的用户访问受保护的资源,但是权限不够,则会进入这个处理器进行处理。

@Component
public class RequestAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request,HttpServletResponse response,AccessDeniedException accessDeniedException) throws IOException {ResponseUtils.result(response,new ResultMsg(403,"权限不足!",null));}
}

UserDetailsService配置

UserDetailsService这个类是用来加载用户信息,包括用户名、密码、权限、角色集合,我们需要实现这个接口,从数据库加载用户信息,代码如下:

@Service
public class JwtTokenUserDetailsService implements UserDetailsService {/*** 查询用户详情的service*/@Autowiredprivate LoginService loginService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//从数据库中查询SecurityUser securityUser = loginService.loadByUsername(username);System.out.println(securityUser);//用户不存在直接抛出UsernameNotFoundException,security会捕获抛出BadCredentialsExceptionif (Objects.isNull(securityUser))throw new UsernameNotFoundException("用户不存在!");return securityUser;}
}

其中的LoginService是根据用户名从数据库中查询出密码、角色、权限,代码如下:

@Service
public class LoginServiceImpl implements LoginService {@Autowiredprivate PasswordEncoder passwordEncoder;@AutowiredTUserService tUserService;@AutowiredTRoleService tRoleService;@Nullable@Overridepublic SecurityUser loadByUsername(String username) {//获取用户信息TUser user = tUserService.getByUsername(username);if (Objects.nonNull(user)){SecurityUser securityUser = new SecurityUser();securityUser.setUsername(username);//todo 此处为了方便,直接在数据库存储的明文,实际生产中应该存储密文,则这里不用再次加密securityUser.setPassword(passwordEncoder.encode(user.getPassword()));//查询该用户的角色List<String> userRoles = tRoleService.selectAllByUsername(username);String[] a={};List<GrantedAuthority> authorityList = AuthorityUtils.createAuthorityList(userRoles.toArray(a));securityUser.setAuthorities(authorityList);return securityUser;}return null;}}

UserDetails这个也是个接口,其中定义了几种方法,都是围绕着用户名、密码、权限+角色集合这三个属性,因此我们可以实现这个类拓展这些字段,SecurityUser代码如下:

@Data
public class SecurityUser implements UserDetails {//用户名private String username;//密码private String password;//权限private Collection<? extends GrantedAuthority> authorities;public SecurityUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {this.username = username;this.password = password;this.authorities = authorities;}public SecurityUser(){}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return authorities;}@Overridepublic String getPassword() {return password;}@Overridepublic String getUsername() {return username;}// 账户是否未过期@Overridepublic boolean isAccountNonExpired() {return true;}// 账户是否未被锁@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}
}

Token校验过滤器

客户端请求头携带了token,服务端肯定是需要针对每次请求解析、校验token,因此必须定义一个Token过滤器,这个过滤器的主要逻辑如下:

  • 从请求头中获取accessToken

  • 对accessToken解析、验签、校验过期时间

  • 校验成功,将authentication存入ThreadLocal中,这样方便后续直接获取用户详细信息。

@Component
public class TokenAuthenticationFilter extends OncePerRequestFilter {/*** JWT的工具类*/@Autowiredprivate JwtUtil jwtUtil;/*** UserDetailsService的实现类,从数据库中加载用户详细信息*/@Qualifier("jwtTokenUserDetailsService")@Autowiredprivate UserDetailsService userDetailsService;@AutowiredRedisTemplate redisTemplate;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {String token = request.getHeader("token");/*** token存在则校验token* 1. token是否存在* 2. token存在:*  2.1 校验token中的用户名是否失效*/if (!StringUtils.isEmpty(token)){DecodedJWT decodedJWT = jwtUtil.getTokenInfo(token);String username;try {username = decodedJWT.getClaim("username").asString();}catch (Exception e){throw new RuntimeException("token无效");}//从redis缓存中获得对应用户数据RedisUser redisUser = (RedisUser) redisTemplate.opsForValue().get(username);String[] a={};List<GrantedAuthority> authorityList = AuthorityUtils.createAuthorityList(redisUser.getAuthorities().toArray(a));UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(redisUser, null,authorityList);authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));// 将 authentication 存入 ThreadLocal,方便后续获取用户信息SecurityContextHolder.getContext().setAuthentication(authentication);}//继续执行下一个过滤器chain.doFilter(request,response);}
}

登录认证过滤器接口配置

上述定义了一个认证过滤器JwtAuthenticationLoginFilter,这个是用来登录的过滤器,但是并没有注入加入Spring Security的过滤器链中,需要定义配置,代码如下:

@Configuration
public class JwtAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {/*** userDetailService*/@Qualifier("jwtTokenUserDetailsService")@Autowiredprivate UserDetailsService userDetailsService;/*** 登录成功处理器*/@Autowiredprivate LoginAuthenticationSuccessHandler loginAuthenticationSuccessHandler;/*** 登录失败处理器*/@Autowiredprivate LoginAuthenticationFailureHandler loginAuthenticationFailureHandler;/*** 加密*/@Autowiredprivate PasswordEncoder passwordEncoder;/*** 将登录接口的过滤器配置到过滤器链中* 1. 配置登录成功、失败处理器* 2. 配置自定义的userDetailService(从数据库中获取用户数据)* 3. 将自定义的过滤器配置到spring security的过滤器链中,配置在UsernamePasswordAuthenticationFilter之前* @param*/@Overridepublic void configure(HttpSecurity http) {JwtAuthenticationLoginFilter filter = new JwtAuthenticationLoginFilter();filter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));//认证成功处理器filter.setAuthenticationSuccessHandler(loginAuthenticationSuccessHandler);//认证失败处理器filter.setAuthenticationFailureHandler(loginAuthenticationFailureHandler);//直接使用DaoAuthenticationProviderDaoAuthenticationProvider provider = new DaoAuthenticationProvider();//设置userDetailServiceprovider.setUserDetailsService(userDetailsService);//设置加密算法provider.setPasswordEncoder(passwordEncoder);http.authenticationProvider(provider);//将这个过滤器添加到UsernamePasswordAuthenticationFilter之前执行http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);}
}

Spring Security全局配置

上述仅仅配置了登录过滤器,还需要在全局配置类做一些配置,如下:

  • 应用登录过滤器的配置

  • 将登录接口、令牌刷新接口放行,不需要拦截

  • 配置AuthenticationEntryPoint、AccessDeniedHandler

  • 禁用session,前后端分离+JWT方式不需要session

  • 将token校验过滤器TokenAuthenticationFilter添加到过滤器链中,放在UsernamePasswordAuthenticationFilter之前。

@Configuration
//@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate JwtAuthenticationSecurityConfig jwtAuthenticationSecurityConfig;@Autowiredprivate EntryPointUnauthorizedHandler entryPointUnauthorizedHandler;@Autowiredprivate RequestAccessDeniedHandler requestAccessDeniedHandler;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin()//禁用表单登录,前后端分离用不上.disable()//应用登录过滤器的配置,配置分离.apply(jwtAuthenticationSecurityConfig).and()// 设置URL的授权.authorizeRequests().antMatchers("/login").permitAll()// anyRequest() 所有请求   authenticated() 必须被认证.anyRequest().authenticated()//处理异常情况:认证失败和权限不足.and().exceptionHandling()//认证未通过,不允许访问异常处理器.authenticationEntryPoint(entryPointUnauthorizedHandler)//认证通过,但是没权限处理器.accessDeniedHandler(requestAccessDeniedHandler).and()//禁用session,JWT校验不需要session.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()//将TOKEN校验过滤器配置到过滤器链中,否则不生效,放到UsernamePasswordAuthenticationFilter之前.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)// 关闭csrf.csrf().disable();}// 自定义的Jwt Token校验过滤器@Beanpublic TokenAuthenticationFilter authenticationTokenFilterBean() {return new TokenAuthenticationFilter();}/*** 加密算法** @return*/@Bean@Overrideprotected AuthenticationManager authenticationManager() throws Exception {return super.authenticationManager();}
}

util包

JWT工具类

@Component
@ConfigurationProperties(prefix = "jwt")
//@Data
public class JwtUtil {private  String signature="cbac";private  Integer expiration=12;/**** 生成token header.payload.signature*/public  String getToken(Map<String,String> payload){Calendar calendar = Calendar.getInstance();calendar.add(Calendar.HOUR, 24);  // 24小时JWTCreator.Builder builder = JWT.create();// 构建payloadpayload.forEach(builder::withClaim);// 指定签发时间、过期时间 和 签名算法,并返回tokenString token = builder.withIssuedAt(new Date()).withExpiresAt(calendar.getTime()).sign(Algorithm.HMAC256(signature));return token;}/**** 获取token信息*/public  DecodedJWT getTokenInfo(String token){DecodedJWT verify=JWT.require(Algorithm.HMAC256(signature)).build().verify(token);return verify;}}

结果封装类

public class ResponseUtils {public static void result(HttpServletResponse response, ResultMsg msg) throws IOException {response.setContentType("application/json;charset=UTF-8");ServletOutputStream out = response.getOutputStream();ObjectMapper objectMapper = new ObjectMapper();out.write(objectMapper.writeValueAsString(msg).getBytes("UTF-8"));out.flush();out.close();}
}

测试结果

项目目录结构

 

http://www.dinnco.com/news/14359.html

相关文章:

  • 青岛网站建设效果无锡网站建设方案优化
  • 网站推他网站360优化大师官方版
  • 静态网站怎么容易做免费网站建站平台
  • 保定企业网站开发电商seo是什么意思
  • 网站建设中 下载买卖友链
  • 专业做pc+手机网站站长工具怎么关闭
  • 绍兴网站建设冯炳良企业网络策划
  • 个人做网站创业竞价外包推广专业公司
  • 2024中国企业500强宁波谷歌seo
  • win2003 iis做网站关键词歌词打印
  • 网站抽奖模块怎么做营销型网站更受用户欢迎的原因是
  • app与网站的区别功能微信软文怎么写
  • 摄影作品网站知乎网站服务器信息查询
  • 免费网站域名cnseo网站优化做什么
  • ptp网站开发网络营销招聘岗位有哪些
  • 做网站用什么语言简单青岛最新消息
  • 做电影网站什么系统好专业seo关键词优化
  • wordpress软件站模板谷歌海外广告投放推广
  • 个体户怎么做购物网站seo搜索引擎
  • 云服务器哪家最便宜湖南关键词优化推荐
  • 做资料网站违法seo优化软件购买
  • 杭州网站建设服务公司百度首页登录入口
  • 河池网站建设服务求职seo推荐
  • 中国动漫影视培训网站源码java培训机构
  • 我想看b站直播苹果手机使用软件提高百度推广排名
  • 电商网站开发的现状百度关键词购买
  • 如何做品牌宣传与推广关键词优化步骤简短
  • 企业网站建设重要性网站seo入门基础教程
  • 手机网站设计图百度自己的宣传广告
  • 小额贷款 网站模板百度推广登录首页官网