Spring Zuul和Spring Security的整合
照搬了https://blog.csdn.net/WiLL_XS/article/details/104894724这篇文章的代码,先谢谢这位老哥,在这些代码的基础上根据自己的需求简化了很多
pom.xml:
<!--zuul 网关组件--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency>
<!--权限安全验证框架--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
<!--token生成工具-->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version></dependency>
以上是必须会用到的jar
项目结构:
代码(都是上面图片结构中的类的代码,直接复制,只要jar没错就不会出错):
package com.wdz.config;import com.wdz.filter.AuthenticationTokenFilter;
import com.wdz.util.exception.EntryPointUnauthorizedHandler;
import com.wdz.util.exception.MyAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration // 声明为配置类
@EnableWebSecurity // 启用 Spring Security web 安全的功能
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {/*** 注册 401 处理器*/@Autowiredprivate EntryPointUnauthorizedHandler unauthorizedHandler;/*** 注册 403 处理器*/@Autowiredprivate MyAccessDeniedHandler accessDeniedHandler;/*** 注册 token 转换拦截器为 bean* 如果客户端传来了 token ,那么通过拦截器解析 token 赋予用户权限** @return* @throws Exception*/@Beanpublic AuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {AuthenticationTokenFilter authenticationTokenFilter = new AuthenticationTokenFilter();authenticationTokenFilter.setAuthenticationManager(authenticationManagerBean());return authenticationTokenFilter;}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/getToken").permitAll() // 所有人可以访问.anyRequest().authenticated() // 必须携带token.and()// 配置被拦截时的处理.exceptionHandling().authenticationEntryPoint(this.unauthorizedHandler) // 添加 token 无效或者没有携带 token 时的处理.accessDeniedHandler(this.accessDeniedHandler) //添加无权限时的处理.and().csrf().disable() // 禁用 Spring Security 自带的跨域处理.sessionManagement() // 定制我们自己的 session 策略.sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 调整为让 Spring Security 不创建和使用 session/*** 本次 json web token 权限控制的核心配置部分* 在 Spring Security 开始判断本次会话是否有权限时的前一瞬间* 通过添加过滤器将 token 解析,将用户所有的权限写入本次会话*/http.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);}
}
这个是controller类,用来获取token的
import com.wdz.entity.ApiUser;
import com.wdz.messgae.JsonResult;
import com.wdz.util.TokenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;@RestController
public class TokenController {//@Autowired//private LoginService loginService;@Autowiredprivate TokenUtils tokenUtils;@PostMapping("/getToken")public JsonResult getToken(@RequestParam String username,@RequestParam String password){ApiUser apiUser=new ApiUser();apiUser.setUsername(username);apiUser.setPassword(password);apiUser.setEnable(1);JsonResult jsonResult=checkApiUser(apiUser,password);if (jsonResult!=null){return jsonResult;}String token=tokenUtils.generateToken(apiUser);return JsonResult.suc(token);}private JsonResult checkApiUser(ApiUser apiUser,String password){if (apiUser==null){return JsonResult.error(434,"账户不存在");}else {if (apiUser.getEnable()==0){return JsonResult.error(452,"账户在黑名单");}if (!apiUser.getPassword().equals(password)){//equals相等返回truereturn JsonResult.error(452,"账户密码错误");}}return null;}}
import com.wdz.util.TokenUtils;
import com.wdz.util.UserDetailImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;/*** @version V1.0.0* @Description 解析 token 的过滤器* 配置在 Spring Security 的配置类中* 用于解析 token ,将用户所有的权限写入本次 Spring Security 的会话中* @Author liuyuequn weanyq@gmail.com* @Date 2017年8月11日10:59:57*/
public class AuthenticationTokenFilter extends UsernamePasswordAuthenticationFilter {/*** json web token 在请求头的名字*/@Value("${token.header}")private String tokenHeader;/*** 辅助操作 token 的工具类*/@Autowiredprivate TokenUtils tokenUtils;/*** Spring Security 的核心操作服务类* 在当前类中将使用 UserDetailsService 来获取 userDetails 对象*///@Autowired//private UserDetailsServiceImpl userDetailsService;@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {// 将 ServletRequest 转换为 HttpServletRequest 才能拿到请求头中的 tokenHttpServletRequest httpRequest = (HttpServletRequest) request;// 尝试获取请求头的 tokenString authToken =httpRequest.getHeader(this.tokenHeader);//获取token=xxx// 尝试拿 token 中的 username// 若是没有 token 或者拿 username 时出现异常,那么 username 为 nullString username = this.tokenUtils.getUsernameFromToken(authToken);// 如果上面解析 token 成功并且拿到了 username 并且本次会话的权限还未被写入if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {// 用 UserDetailsService 从数据库中拿到用户的 UserDetails 类// UserDetails 类是 Spring Security 用于保存用户权限的实体类UserDetails userDetails = new UserDetailImpl();// 检查用户带来的 token 是否有效// 包括 token 和 userDetails 中用户名是否一样, token 是否过期, token 生成时间是否在最后一次密码修改时间之前// 若是检查通过//if (this.tokenUtils.validateToken(authToken, userDetails)) {// 生成通过认证UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));// 将权限写入本次会话SecurityContextHolder.getContext().setAuthentication(authentication);// }//if (!userDetails.isEnabled()){// response.setCharacterEncoding("UTF-8");// response.setContentType("application/json;charset=UTF-8");//response.getWriter().print("{\"code\":\"452\",\"data\":\"\",\"message\":\"账号处于黑名单\"}");//return;// }}chain.doFilter(request, response);}}
public enum JsonCode {/* 成功状态码 */SUCCESS(0, "成功"),/* 失败状态码 */FAILED(9001,"失败"),/* 错误状态码 */ERROR(9002,"不存在该资源,请检查参数是否正确。");private Integer code;private String message;JsonCode(Integer code, String message) {this.code = code;this.message = message;}public Integer code() {return this.code;}public String message() {return this.message;}public static String getMessage(String name) {for (JsonCode item : JsonCode.values()) {if (item.name().equals(name)) {return item.message;}}return name;}public static Integer getCode(String name) {for (JsonCode item : JsonCode.values()) {if (item.name().equals(name)) {return item.code;}}return null;}@Overridepublic String toString() {return this.name();}}
public class JsonResult<T> {private Integer code;private String msg;private T data;//操作成功,有data数据public static JsonResult suc(Object data) {JsonResult result = new JsonResult();result.setResultCode(JsonCode.SUCCESS);result.setData(data);return result;}//运行错误,数据库连接错误public static JsonResult error() {JsonResult result = new JsonResult();result.setResultCode(JsonCode.ERROR);return result;}//运行错误,数据库连接错误public static JsonResult error(Integer code,String msg) {JsonResult result = new JsonResult();result.setCode(code);result.setMsg(msg);return result;}private void setResultCode(JsonCode code) {this.code = code.code();this.msg = code.message();}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public T getData() {return data;}public void setData(T data) {this.data = data;}
}
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component
public class EntryPointUnauthorizedHandler implements AuthenticationEntryPoint {/*** 未登录或无权限时触发的操作* 返回 {"code":401,"message":"没有携带 token 或者 token 无效!","data":""}* @param httpServletRequest* @param httpServletResponse* @param e* @throws IOException* @throws ServletException*/@Overridepublic void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {//返回json形式的错误信息httpServletResponse.setCharacterEncoding("UTF-8");httpServletResponse.setContentType("application/json");httpServletResponse.getWriter().println("{\"code\":401,\"message\":\"没有携带 token 或者 token 无效!\",\"data\":\"\"}");httpServletResponse.getWriter().flush();}}
public interface TokenDetail {// 这里封装了一层,不直接使用 username 做参数的原因是可以方便未来增加其他要封装到 token 中的信息String getUsername();
}
import com.wdz.entity.ApiUser;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;import java.util.Collection;
import java.util.Date;public class SecurityModelFactory {public static UserDetailImpl create(ApiUser user) {Collection<? extends GrantedAuthority> authorities;try {authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(user.getAuthorities());} catch (Exception e) {authorities = null;}return new UserDetailImpl(user.getUsername(),user.getUsername(),user.getPassword(),authorities,user.enable());}}
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;import java.util.Collection;
import java.util.Date;/*** @version V1.0.0* @Description 实现了 UserDetails 接口的模型类* 拓展了 UserDetails 的属性* 可以承载 创建 token 的日期,和 token 过期的日期* 用于判断用户传来的 token 是否可用* @Author liuyuequn weanyq@gmail.com* @Date 2017/8/2 19:03*/
public class UserDetailImpl implements UserDetails {// 开始定义必要的属性private String id;private String username;private String password;private Collection<? extends GrantedAuthority> authorities;private Boolean enabled;// 必要的属性定义完毕//开始定义 UserDetails 必要的属性,因为不打算启用这些限制条件,所以不对这些条件做限制,全部设置为 true (通过)private Boolean accountNonExpired = true;private Boolean accountNonLocked = true;private Boolean credentialsNonExpired = true;// 结束定义 UserDetails 必要的属性public UserDetailImpl() {super();}public UserDetailImpl(String id, String username, String password, Collection<? extends GrantedAuthority> authorities, Boolean enabled) {this.setId(id);this.setUsername(username);this.setPassword(password);this.setAuthorities(authorities);this.enabled = enabled;}public String getId() {return this.id;}public void setId(String id) {this.id = id;}public String getUsername() {return this.username;}public void setUsername(String username) {this.username = username;}@JsonIgnorepublic String getPassword() {return this.password;}public void setPassword(String password) {this.password = password;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return this.authorities;}public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {this.authorities = authorities;}@JsonIgnorepublic Boolean getAccountNonExpired() {return this.accountNonExpired;}public void setAccountNonExpired(Boolean accountNonExpired) {this.accountNonExpired = accountNonExpired;}@Overridepublic boolean isAccountNonExpired() {return this.getAccountNonExpired();}@JsonIgnorepublic Boolean getAccountNonLocked() {return this.accountNonLocked;}public void setAccountNonLocked(Boolean accountNonLocked) {this.accountNonLocked = accountNonLocked;}@Overridepublic boolean isAccountNonLocked() {return this.getAccountNonLocked();}@JsonIgnorepublic Boolean getCredentialsNonExpired() {return this.credentialsNonExpired;}public void setCredentialsNonExpired(Boolean credentialsNonExpired) {this.credentialsNonExpired = credentialsNonExpired;}@Overridepublic boolean isCredentialsNonExpired() {return this.getCredentialsNonExpired();}@JsonIgnorepublic Boolean getEnabled() {return this.enabled;}public void setEnabled(Boolean enabled) {this.enabled = enabled;}@Overridepublic boolean isEnabled() {return this.getEnabled();}}
application.yml:
# 构建路由地址
zuul:routes:# 这里可以自定义article:# 匹配的路由规则path: /**# 路由的目标服务名serviceId: article#访问本项目的接口需要这样写,getToken:path: /getToken/**url: forward:/getToken
token:secret: xsexpiration: 3600header: X_Auth_Token
Spring Zuul和Spring Security的整合相关推荐
- [摘]Spring 3之MVC Security简单整合开发
为什么80%的码农都做不了架构师?>>> 参见: http://sarin.javaeye.com/blog/829738 转载于:https://my.oschina.net ...
- Spring Security OAuth2整合JWT
文章目录 1. Spring Security 与 OAuth2 2. Spring Security OAuth2的配置和使用 ①:引入依赖 ②:配置 spring security ③:配置授权服 ...
- JWT实战 Spring Security Oauth2整合JWT 整合SSO单点登录
文章目录 一.JWT 1.1 什么是JWT 1.2 JWT组成 头部(header) 载荷(payload) 签名(signature) 如何应用 1.3 JJWT 快速开始 创建token toke ...
- Spring Security(5) 整合OAuth2
文章目录 一.前言 二.什么是OAuth2? 三.应用场景 四.三部分 五.四种授权模式 1. 授权码模式(authorization code) 2. 简化模式(implicit) 3. 密码模式( ...
- Spring Security 4 整合Hibernate 实现持久化登录验证(带源码)
上一篇文章:Spring Security 4 整合Hibernate Bcrypt密码加密(带源码) 原文地址:http://websystique.com/spring-security/spri ...
- spring cloud alibaba 全家桶详细整合
文章目录 本项目代码仓库地址 一.此次版本信息说明: 二.组件说明 三.新建聚合工程 3.1父工程pom文件 四.搭建整合nacos 五. 整合nacos 注册中心,新建cloud-system模块 ...
- JAVAspringboot微服务b2b Spring MVC+mybatis+spring cloud+spring boot+spring security
鸿鹄云商大型企业分布式互联网电子商务平台,推出PC+微信+APP+云服务的云商平台系统,其中包括B2B.B2C.C2C.O2O.新零售.直播电商等子平台. 分布式.微服务.云架构电子商务平台 java ...
- java电子商务系统源码 Spring MVC+mybatis+spring cloud+spring boot+spring security
鸿鹄云商大型企业分布式互联网电子商务平台,推出PC+微信+APP+云服务的云商平台系统,其中包括B2B.B2C.C2C.O2O.新零售.直播电商等子平台. 分布式.微服务.云架构电子商务平台 java ...
- 【Spring Cloud Alibaba 实战 | 总结篇】Spring Cloud Gateway + Spring Security OAuth2 + JWT 实现微服务统一认证授权和鉴权
一. 前言 hi,大家好~ 好久没更文了,期间主要致力于项目的功能升级和问题修复中,经过一年时间这里只贴出关键部分代码的打磨,[有来]终于迎来v2.0版本,相较于v1.x版本主要完善了OAuth2认证 ...
最新文章
- python turtle库画图案-Python:turtle库的使用及图形绘制
- 三十三、深入Python中的itertools模块
- 安川机器人焊枪切换设定方法_安川机器人参数更改方法
- 批量删除指定user和transaction type对应order的report
- 深入Java核心:JVM中的栈和局部变量
- 关于近期对自己的总结
- Unity2020.2中支持的C#8有什么新特性?
- 开源视频平台:Kaltura
- oracle如何查找谁删除了数据_php如何删除session中数据
- C++11的std::declval与decltype
- 计算机界面没磁盘驱动器,驱动器中没有磁盘的原因和解决办法
- Java基础加强重温_06:可变参数、集合工具类Collections类、冒泡排序、Map集合、Map集合遍历、Map案例、LinkedHashMap集合、图书管理系统
- C++实现客户机(CLIENT)类
- 【OR】S Lemma
- 【bzoj1150】【CSTC2007】【数据备份】【贪心】
- 【Charles】charles unknown问题解决,及手机代理设置【iOS手机】
- 【NIPS 2017】PointNet++:度量空间中点集的深层次特征学习
- 金庸笔下用脚发暗器_移动的艺术:使用明暗器图创建动画材质
- 医疗行业大数据应用的三个案例
- Web安全之:WebShell的获取与查杀