软件编程
位置:首页>> 软件编程>> java编程>> spring security在分布式项目下的配置方法(案例详解)

spring security在分布式项目下的配置方法(案例详解)

作者:蓝天白水  发布时间:2022-12-26 03:45:49 

标签:spring,security,分布式

分布式项目和传统项目的区别就是,分布式项目有多个服务,每一个服务仅仅只实现一套系统中一个或几个功能,所有的服务组合在一起才能实现系统的完整功能。这会产生一个问题,多个服务之间session不能共享,你在其中一个服务中登录了,登录信息保存在这个服务的session中,别的服务不知道啊,所以你访问别的服务还得在重新登录一次,对用户十分不友好。为了解决这个问题,于是就产生了单点登录:

**jwt单点登录:**就是用户在登录服务登录成功后,登录服务会产生向前端响应一个token(令牌),以后用户再访问系统的资源的时候都要带上这个令牌,各大服务对这个令牌进行验证(令牌是否过期,令牌是否被篡改),验证通过了,可以访问资源,同时,令牌中也会携带一些不重要的信息,比如用户名,权限。通过解析令牌就能知道当前登录的用户和用户所拥有的权限。

下面我们就来写一个案例项目看看具体如何使用

1 创建项目结构

 1.1 父工程cloud-security

这是父工程所需要的包


<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/>
</parent>

<dependencies>

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>

1.2 公共工程 security-common

这是公共工程所需要的包


<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>

<!--jwt所需包-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>

1.3 认证服务security-sever

这个服务仅仅只有两项功能:

(1)用户登录,颁发令牌

(2)用户注册

我们这里只实现第一个功能

1.3.1 认证服务所需的包


<dependency>
<groupId>cn.lx.security</groupId>
<artifactId>security-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--通用mapper-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

1.3.2 配置application.yml

这里面的配置没什么好说的,都很简单


server:
port: 8080

spring:
datasource:
url: jdbc:mysql:///security_authority?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password:
driver-class-name: com.mysql.cj.jdbc.Driver
thymeleaf:
cache: false
main:
allow-bean-definition-overriding: true

mybatis:
type-aliases-package: cn.lx.security.doamin
configuration:
#驼峰
map-underscore-to-camel-case: true

logging:
level:
cn.lx.security: debug

1.3.3 导入domain,dao,service,config

这个可以在上篇文档中找到,我们只需要service中的loadUserByUsername方法及其所调用dao中的方法

完整项目在我的github中,地址:git@github.com:lx972/cloud-security.git

配置文件我们也从上篇中复制过来MvcConfig,SecurityConfig

1.3.4 测试

访问http://localhost:8080/loginPage成功出现登录页面,说明认证服务的骨架搭建成功了

1.4 资源服务security-resource1

实际项目中会有很多资源服务,我只演示一个

为了简单,资源服务不使用数据库

1.4.1 资源服务所需的包


<dependency>
<groupId>cn.lx.security</groupId>
<artifactId>security-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

1.4.2 配置application.yml


server:
port: 8090

logging:
level:
cn.lx.security: debug

1.4.3 controller

拥有ORDER_LIST权限的才能访问


@RestController
@RequestMapping("/order")
public class OrderController {

//@Secured("ORDER_LIST")
@PreAuthorize(value = "hasAuthority('ORDER_LIST')")
@RequestMapping("/findAll")
public String findAll(){
 return "order-list";
}
}

拥有PRODUCT_LIST权限的才能访问


@RestController
@RequestMapping("/product")
public class ProductController {

//@Secured("PRODUCT_LIST")
@PreAuthorize(value = "hasAuthority('PRODUCT_LIST')")
@RequestMapping("/findAll")
public String findAll(){
 return "product-list";
}
}

1.4.4 security配置类


@Configuration
@EnableWebSecurity
//这个注解先不要加
//@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

/**
 * Override this method to configure the {@link HttpSecurity}. Typically subclasses
 * should not invoke this method by calling super as it may override their
 * configuration. The default configuration is:
 *
 * <pre>
 * http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
 * </pre>
 *
 * @param http the {@link HttpSecurity} to modify
 * @throws Exception if an error occurs
 */
@Override
protected void configure(HttpSecurity http) throws Exception {
 http
   .csrf().disable()
   .authorizeRequests().anyRequest().authenticated();
}
}

1.4.5 测试

访问http://localhost:8090/order/findAll成功打印出order-list,服务搭建成功。

2 认证服务实现登录,颁发令牌

首先,我们必须知道我们的项目是前后端分离的项目,所以我们不能由后端控制页面跳转了,只能返回json串通知前端登录成功,然后前端根据后端返回的信息控制页面跳转。

2.1 登录成功或者登录失败后的源码分析

UsernamePasswordAuthenticationFilter中登录成功后走successfulAuthentication方法


/**
* Default behaviour for successful authentication.认证成功之后的默认操作
* <ol>
* <li>Sets the successful <tt>Authentication</tt> object on the
* {@link SecurityContextHolder}</li>
* <li>Informs the configured <tt>RememberMeServices</tt> of the successful login</li>
* <li>Fires an {@link InteractiveAuthenticationSuccessEvent} via the configured
* <tt>ApplicationEventPublisher</tt></li>
* <li>Delegates additional behaviour to the {@link AuthenticationSuccessHandler}.</li>
* </ol>
*
* Subclasses can override this method to continue the {@link FilterChain} after
* successful authentication.
* @param request
* @param response
* @param chain
* @param authResult the object returned from the <tt>attemptAuthentication</tt>
* method.
* @throws IOException
* @throws ServletException
*/
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {

if (logger.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: "
+ authResult);
}

//将已通过认证的Authentication保存到securityContext容器中,应为后面的过滤器需要使用
SecurityContextHolder.getContext().setAuthentication(authResult);

//记住我
rememberMeServices.loginSuccess(request, response, authResult);

// Fire event
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
authResult, this.getClass()));
}

//这个方法你点进去,就会发现,真正作业面跳转是在这里
successHandler.onAuthenticationSuccess(request, response, authResult);
}

UsernamePasswordAuthenticationFilter中登录成功后走unsuccessfulAuthentication方法


/**
* Default behaviour for unsuccessful authentication.认证失败之后的默认操作
* <ol>
* <li>Clears the {@link SecurityContextHolder}</li>
* <li>Stores the exception in the session (if it exists or
* <tt>allowSesssionCreation</tt> is set to <tt>true</tt>)</li>
* <li>Informs the configured <tt>RememberMeServices</tt> of the failed login</li>
* <li>Delegates additional behaviour to the {@link AuthenticationFailureHandler}.</li>
* </ol>
*/
protected void unsuccessfulAuthentication(HttpServletRequest request,
HttpServletResponse response, AuthenticationException failed)
throws IOException, ServletException {
SecurityContextHolder.clearContext();

if (logger.isDebugEnabled()) {
logger.debug("Authentication request failed: " + failed.toString(), failed);
logger.debug("Updated SecurityContextHolder to contain null Authentication");
logger.debug("Delegating to authentication failure handler " + failureHandler);
}

//记住我失败
rememberMeServices.loginFail(request, response);

//失败后的页面跳转都在这里
failureHandler.onAuthenticationFailure(request, response, failed);
}

2.2 重写successfulAuthentication和unsuccessfulAuthentication方法

我们继承UsernamePasswordAuthenticationFilter这个过滤器


public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {

/**
 * 这个方法必须有
 * 在过滤器创建的时候手动将AuthenticationManager对象给这个过滤器使用
 * @param authenticationManager 这个对象在自己写的SecurityConfig里面
 */
public AuthenticationFilter(AuthenticationManager authenticationManager) {
 super.setAuthenticationManager(authenticationManager);
}

/**
 * Default behaviour for successful authentication.认证成功之后的默认操作
 * @param request
 * @param response
 * @param chain
 * @param authResult the object returned from the <tt>attemptAuthentication</tt>
 *     method.
 * @throws IOException
 * @throws ServletException
 */
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {

//认证成功的对象放入securityContext容器中
 SecurityContextHolder.getContext().setAuthentication(authResult);

// Fire event
 if (this.eventPublisher != null) {
  eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
    authResult, this.getClass()));
 }
 //创建令牌
 Map<String, Object> claims=new HashMap<>();
 SysUser sysUser = (SysUser) authResult.getPrincipal();
 claims.put("username",sysUser.getUsername());
 claims.put("authorities",authResult.getAuthorities());
 //这个方法在下面介绍
 String jwt = JwtUtil.createJwt(claims);
 //直接返回json
 ResponseUtil.responseJson(new Result("200", "登录成功",jwt),response);
}

/**
 * Default behaviour for unsuccessful authentication.
 * @param request
 * @param response
 * @param failed
 */
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
  //清理容器中保存的认证对象
 SecurityContextHolder.clearContext();
 //直接返回json
 ResponseUtil.responseJson(new Result("500", "登录失败"),response);

}
}

2.3 令牌创建


String jwt = JwtUtil.createJwt(claims);

这个方法干了什么事呢


/**
 * 创建令牌
 * @param claims
 * @return
 */
public static String createJwt(Map<String, Object> claims){
//获取私钥
String priKey = KeyUtil.readKey("privateKey.txt");
//将string类型的私钥转换成PrivateKey,jwt只能接受PrivateKey的私钥
PKCS8EncodedKeySpec priPKCS8 = null;
try {
 priPKCS8 = new PKCS8EncodedKeySpec(new BASE64Decoder().decodeBuffer(priKey));
 KeyFactory keyf = KeyFactory.getInstance("RSA");
 PrivateKey privateKey = keyf.generatePrivate(priPKCS8);
 //创建令牌
 String jws = Jwts.builder()
  //设置令牌过期时间30分钟
  .setExpiration(new Date(System.currentTimeMillis()+1000*60*30))
  //为令牌设置额外的信息,这里我们设置用户名和权限,还可以根据需要继续添加
  .addClaims(claims)
  //指定加密类型为rsa
  .signWith(privateKey, SignatureAlgorithm.RS256)
  //得到令牌
  .compact();
 log.info("创建令牌成功:"+jws);
 return jws;
} catch (Exception e) {
 throw new RuntimeException("创建令牌失败");
}
}

获取秘钥的方法


public class KeyUtil {

/**
 * 读取秘钥
 * @param keyName
 * @return
 */
public static String readKey(String keyName){
 //文件必须放在resources根目录下
 ClassPathResource resource=new ClassPathResource(keyName);
 String key =null;
 try {
  InputStream is = resource.getInputStream();
  key = StreamUtils.copyToString(is, Charset.defaultCharset());
 }catch (Exception e){
  throw new RuntimeException("读取秘钥错误");
 }
 if (key==null){
  throw new RuntimeException("秘钥为空");
 }
 return key;
}
}

2.4 响应json格式数据给前端

封装成了一个工具类


public class ResponseUtil {

/**
 * 将结果以json格式返回
 * @param result 返回结果
 * @param response
 * @throws IOException
 */
public static void responseJson(Result result, HttpServletResponse response) throws IOException {
 response.setContentType("application/json;charset=utf-8");
 response.setStatus(200);
 PrintWriter writer = response.getWriter();
 writer.write(JSON.toJSONString(result));
 writer.flush();
 writer.close();
}
}

返回结果


@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result {

private String code;
private String msg;
private Object data;

public Result(String code, String msg) {
 this.code = code;
 this.msg = msg;
}
}

3 认证服务实现令牌验证和解析

除了security配置类中配置的需要忽略的请求之外,其他所有请求必须验证请求头中是否携带令牌,没有令牌直接响应json数据,否则就验证和解析令牌。

security中有一个过滤器是实现令牌BasicAuthenticationFilter认证的,只不过他是basic的,没关系,我们继承它,然后重写解析basic的方法

3.1 源码分析


@Override
protected void doFilterInternal(HttpServletRequest request,
       HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
final boolean debug = this.logger.isDebugEnabled();

//获取请求头中Authorization的值
String header = request.getHeader("Authorization");

if (header == null || !header.toLowerCase().startsWith("basic ")) {
 //值不符合条件直接放行
 chain.doFilter(request, response);
 return;
}

try {
 //就是解析Authorization
 String[] tokens = extractAndDecodeHeader(header, request);
 assert tokens.length == 2;

//tokens[0]用户名 tokens[1]密码
 String username = tokens[0];

if (debug) {
  this.logger
   .debug("Basic Authentication Authorization header found for user '"
     + username + "'");
 }

//判断是否需要认证(容器中有没有该认证对象)
 if (authenticationIsRequired(username)) {
  //创建一个对象
  UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
   username, tokens[1]);
  authRequest.setDetails(
   this.authenticationDetailsSource.buildDetails(request));
  //进行认证,我们不关心它如何认证,我们需要按自己的方法对令牌认证解析
  Authentication authResult = this.authenticationManager
   .authenticate(authRequest);

if (debug) {
   this.logger.debug("Authentication success: " + authResult);
  }

//已认证的对象保存到securityContext中
  SecurityContextHolder.getContext().setAuthentication(authResult);

//记住我
  this.rememberMeServices.loginSuccess(request, response, authResult);

onSuccessfulAuthentication(request, response, authResult);
 }

}
catch (AuthenticationException failed) {
 SecurityContextHolder.clearContext();

if (debug) {
  this.logger.debug("Authentication request for failed: " + failed);
 }

this.rememberMeServices.loginFail(request, response);

onUnsuccessfulAuthentication(request, response, failed);

if (this.ignoreFailure) {
  chain.doFilter(request, response);
 }
 else {
  this.authenticationEntryPoint.commence(request, response, failed);
 }

return;
}

chain.doFilter(request, response);
}

3.2 重写doFilterInternal方法

继承BasicAuthenticationFilter


public class TokenVerifyFilter extends BasicAuthenticationFilter {

/**
 * Creates an instance which will authenticate against the supplied
 * {@code AuthenticationManager} and which will ignore failed authentication attempts,
 * allowing the request to proceed down the filter chain.
 * 在过滤器创建的时候手动将AuthenticationManager对象给这个过滤器使用
 * @param authenticationManager 这个对象在自己写的SecurityConfig里面
 */
public TokenVerifyFilter(AuthenticationManager authenticationManager) {
 super(authenticationManager);
}

/**
 * 过滤请求,判断是否携带令牌
 * @param request
 * @param response
 * @param chain
 * @throws IOException
 * @throws ServletException
 */
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

String header = request.getHeader("Authorization");

if (header == null || !header.toLowerCase().startsWith("bearer ")) {
  //直接返回json
  ResponseUtil.responseJson(new Result("403", "用户未登录"),response);
  return;
 }

//得到jwt令牌
 String jwt = StringUtils.replace(header, "bearer ", "");
 //解析令牌
 String[] tokens = JwtUtil.extractAndDecodeJwt(jwt);

//用户名
 String username = tokens[0];
 //权限
 List<SysPermission> authorities= JSON.parseArray(tokens[1], SysPermission.class);

UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
   username,
   null,
   authorities
   );

//放入SecurityContext容器中
 SecurityContextHolder.getContext().setAuthentication(authRequest);

chain.doFilter(request, response);
}
}

3.3 验证解析令牌


/**
 * 解析令牌
 * @param compactJws
 * @return
 */
public static String decodeJwt(String compactJws){
//获取公钥
String pubKey = KeyUtil.readKey("publicKey.txt");
//将string类型的私钥转换成PublicKey,jwt只能接受PublicKey的公钥
KeyFactory keyFactory;
try {
 X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(
  new BASE64Decoder().decodeBuffer(pubKey));

keyFactory = KeyFactory.getInstance("RSA");
 PublicKey publicKey = keyFactory.generatePublic(bobPubKeySpec);

Claims body = Jwts.parserBuilder().setSigningKey(publicKey).build().parseClaimsJws(compactJws).getBody();

String jwtString = JSON.toJSONString(body);

//OK, we can trust this JWT
 log.info("解析令牌成功:"+jwtString);
 return jwtString;
} catch (Exception e) {
 throw new RuntimeException("解析令牌失败");
}
}

/**
 * 解析令牌并获取用户名和权限
 * @param compactJws
 * @return String[0]用户名
 * String[1]权限
 */
public static String[] extractAndDecodeJwt(String compactJws){
//获取令牌的内容
String decodeJwt = decodeJwt(compactJws);
JSONObject jsonObject = JSON.parseObject(decodeJwt);
String username = jsonObject.getString("username");
String authorities = jsonObject.getString("authorities");
return new String[] { username, authorities };
}

3.4 修改security配置类

将自定义过滤器加入过滤器链


@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private IUserService iUserService;

@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;

/**
 * 只有这个配置类有AuthenticationManager对象,我们要把这个类中的这个对象放入容器中
 * 这样在别的地方就可以自动注入了
 * @return
 * @throws Exception
 */
@Bean
@Override
public AuthenticationManager authenticationManager() throws Exception {
 AuthenticationManager authenticationManager = super.authenticationManagerBean();
 return authenticationManager;
}

/**
 * Used by the default implementation of {@link #authenticationManager()} to attempt
 * to obtain an {@link AuthenticationManager}. If overridden, the
 * {@link AuthenticationManagerBuilder} should be used to specify the
 * {@link AuthenticationManager}.
 *
 * <p>
 * The {@link #authenticationManagerBean()} method can be used to expose the resulting
 * {@link AuthenticationManager} as a Bean. The {@link #userDetailsServiceBean()} can
 * be used to expose the last populated {@link UserDetailsService} that is created
 * with the {@link AuthenticationManagerBuilder} as a Bean. The
 * {@link UserDetailsService} will also automatically be populated on
 * {@link HttpSecurity#getSharedObject(Class)} for use with other
 * {@link SecurityContextConfigurer} (i.e. RememberMeConfigurer )
 * </p>
 *
 * <p>
 * For example, the following configuration could be used to register in memory
 * authentication that exposes an in memory {@link UserDetailsService}:
 * </p>
 *
 * <pre>
 * &#064;Override
 * protected void configure(AuthenticationManagerBuilder auth) {
 * auth
 * // enable in memory based authentication with a user named
 * // &quot;user&quot; and &quot;admin&quot;
 * .inMemoryAuthentication().withUser(&quot;user&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;).and()
 * .withUser(&quot;admin&quot;).password(&quot;password&quot;).roles(&quot;USER&quot;, &quot;ADMIN&quot;);
 * }
 *
 * // Expose the UserDetailsService as a Bean
 * &#064;Bean
 * &#064;Override
 * public UserDetailsService userDetailsServiceBean() throws Exception {
 * return super.userDetailsServiceBean();
 * }
 *
 * </pre>
 *
 * @param auth the {@link AuthenticationManagerBuilder} to use
 * @throws Exception
 */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
 //在内存中注册一个账号
 //auth.inMemoryAuthentication().withUser("user").password("{noop}123").roles("USER");
 //连接数据库,使用数据库中的账号
 auth.userDetailsService(iUserService).passwordEncoder(bCryptPasswordEncoder);

}

/**
 * Override this method to configure {@link WebSecurity}. For example, if you wish to
 * ignore certain requests.
 *
 * @param web
 */
@Override
public void configure(WebSecurity web) throws Exception {
 web.ignoring().antMatchers("/css/**",
   "/img/**",
   "/plugins/**",
   "/favicon.ico",
   "/loginPage");
}

/**
 * Override this method to configure the {@link HttpSecurity}. Typically subclasses
 * should not invoke this method by calling super as it may override their
 * configuration. The default configuration is:
 *
 * <pre>
 * http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
 * </pre>
 *
 * @param http the {@link HttpSecurity} to modify
 * @throws Exception if an error occurs
 */
@Override
protected void configure(HttpSecurity http) throws Exception {
 http.csrf().disable()
   .httpBasic()
   .and()
   .authorizeRequests()
   .anyRequest().authenticated()
   .and()
   /**
    * 不要将自定义过滤器加component注解,而是在这里直接创建一个过滤器对象加入到过滤器链中,并传入authenticationManager
    * 启动后,过滤器链中会同时出现自定义过滤器和他的父类,他会自动覆盖,并不会过滤两次
    *
    * 使用component注解会产生很多问题:
    * 1. web.ignoring()会失效,上面的资源还是会经过自定义的过滤器
    * 2.过滤器链中出现的是他们父类中的名字
    * 3.登录的时候(访问/login),一直使用匿名访问,不会去数据库中查询
    */
   .addFilterAt(new AuthenticationFilter(super.authenticationManager()), UsernamePasswordAuthenticationFilter.class)
   .addFilterAt(new TokenVerifyFilter(super.authenticationManager()), BasicAuthenticationFilter.class)
   //.formLogin().loginPage("/login.jsp").loginProcessingUrl("/login").defaultSuccessUrl("/index.jsp").failureForwardUrl("/failer.jsp").permitAll()
   .formLogin().loginPage("/loginPage").loginProcessingUrl("/login").permitAll()
   .and()
   .logout().logoutUrl("/logout").logoutSuccessUrl("/loginPage").invalidateHttpSession(true).permitAll();
}
}

4 资源服务实现令牌验证和解析

复制认证服务的TokenVerifyFilter到资源服务

然后修改security的配置文件


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
 * Override this method to configure the {@link HttpSecurity}. Typically subclasses
 * should not invoke this method by calling super as it may override their
 * configuration. The default configuration is:
 *
 * <pre>
 * http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
 * </pre>
 *
 * @param http the {@link HttpSecurity} to modify
 * @throws Exception if an error occurs
 */
@Override
protected void configure(HttpSecurity http) throws Exception {
 http
   .csrf().disable()
   .authorizeRequests().anyRequest().authenticated()
   .and()
   //禁用session
   .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
   .and()
  //添加自定义过滤器
   .addFilterAt(new TokenVerifyFilter(super.authenticationManager()), BasicAuthenticationFilter.class);
}
}

来源:https://blog.csdn.net/qq_33012981/article/details/108990530

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com