在我的用户密码授权文章里介绍了spring-security的工作过程,不了解的同学,可以先看看用户密码授权这篇文章,在

用户密码授权模式里,主要是通过一个登陆页进行授权,然后把授权对象写到session里,它主要用在mvc框架里,而对于webapi来说,一般不会采用这种方式,对于webapi

来说,一般会用jwt授权方式,就是token授权码的方式,每访问api接口时,在http头上带着你的token码,而大叔自己也写了一个简单的jwt授权模式,下面介绍一下。

WebSecurityConfig授权配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* token过滤器.
*/
@Autowired
LindTokenAuthenticationFilter lindTokenAuthenticationFilter; @Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
} @Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
// 基于token,所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
// 对于获取token的rest api要允许匿名访问
.antMatchers("/lind-auth/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated();
httpSecurity
.addFilterBefore(lindTokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
// 禁用缓存
httpSecurity.headers().cacheControl();
} /**
* 密码生成策略.
*
* @return
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

授权接口login

对外开放的,需要提供用户名和密码为参数进行登陆,然后返回token码,当然也可以使用手机号和验证码登陆,授权逻辑是一样的,获取用户信息都是使用UserDetailsService,

然后开发人员根据自己的业务去重写loadUserByUsername来获取用户实体。

用户登陆成功后,为它授权及认证,这一步我们会在redis里建立token与用户名的关系。

@GetMapping(LOGIN)
public ResponseEntity<?> refreshAndGetAuthenticationToken(
@RequestParam String username,
@RequestParam String password) throws AuthenticationException {
return ResponseEntity.ok(generateToken(username, password));
} /**
* 登陆与授权.
*
* @param username .
* @param password .
* @return
*/
private String generateToken(String username, String password) {
UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password);
// Perform the security
final Authentication authentication = authenticationManager.authenticate(upToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
// Reload password post-security so we can generate token
final UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// 持久化的redis
String token = CommonUtils.encrypt(userDetails.getUsername());
redisTemplate.opsForValue().set(token, userDetails.getUsername());
return token;
}

LindTokenAuthenticationFilter代码

主要实现了对请求的拦截,获取http头上的Authorization元素,token码就在这个键里,我们的token都是采用通用的Bearer开头,当你的token没有过期时,会

存储在redis里,key就是用户名的md5码,而value就是用户名,当拿到token之后去数据库或者缓存里拿用户信息进行授权即可。

/**
* token filter bean.
*/
@Component
public class LindTokenAuthenticationFilter extends OncePerRequestFilter { @Autowired
RedisTemplate<String, String> redisTemplate;
String tokenHead = "Bearer ";
String tokenHeader = "Authorization";
@Autowired
private UserDetailsService userDetailsService; /**
* token filter.
*
* @param request .
* @param response .
* @param filterChain .
*/
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException { String authHeader = request.getHeader(this.tokenHeader);
if (authHeader != null && authHeader.startsWith(tokenHead)) {
final String authToken = authHeader.substring(tokenHead.length()); // The part after "Bearer "
if (authToken != null && redisTemplate.hasKey(authToken)) {
String username = redisTemplate.opsForValue().get(authToken);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
//可以校验token和username是否有效,目前由于token对应username存在redis,都以默认都是有效的
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(
request));
logger.info("authenticated user " + username + ", setting security context");
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
} filterChain.doFilter(request, response); }

测试token授权

get:http://localhost:8080/lind-demo/login?username=admin&password=123

post:http://localhost:8080/lind-demo/user/add
Content-Type:application/json
Authorization:Bearer 21232F297A57A5A743894A0E4A801FC3

spring-security实现的token授权的更多相关文章

  1. 使用Redis作为Spring Security OAuth2的token存储

    写在前边 本文对Spring Security OAuth2的token使用Redis保存,相比JWT实现的token存储,Redis可以随时吊销access_token,并且Redis响应速度很快, ...

  2. Spring Security实现OAuth2.0授权服务 - 进阶版

    <Spring Security实现OAuth2.0授权服务 - 基础版>介绍了如何使用Spring Security实现OAuth2.0授权和资源保护,但是使用的都是Spring Sec ...

  3. Spring Security OAuth2.0认证授权二:搭建资源服务

    在上一篇文章[Spring Security OAuth2.0认证授权一:框架搭建和认证测试](https://www.cnblogs.com/kuangdaoyizhimei/p/14250374. ...

  4. Spring Security OAuth2.0认证授权三:使用JWT令牌

    Spring Security OAuth2.0系列文章: Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二: ...

  5. Spring Security OAuth2.0认证授权四:分布式系统认证授权

    Spring Security OAuth2.0认证授权系列文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授 ...

  6. Spring Security OAuth2.0认证授权五:用户信息扩展到jwt

    历史文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二:搭建资源服务 Spring Security OA ...

  7. Spring Security OAuth2.0认证授权六:前后端分离下的登录授权

    历史文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二:搭建资源服务 Spring Security OA ...

  8. Spring Security OAuth 格式化 token 输出

    个性化token 背景 上一篇文章<Spring Security OAuth 个性化token(一)>有提到,oauth2.0 接口默认返回的报文格式如下: {     "ac ...

  9. 使用JWT作为Spring Security OAuth2的token存储

    序 Spring Security OAuth2的demo在前几篇文章中已经讲过了,在那些模式中使用的都是RemoteTokenService调用授权服务器来校验token,返回校验通过的用户信息供上 ...

  10. Spring Security实现OAuth2.0授权服务 - 基础版

    一.OAuth2.0协议 1.OAuth2.0概述 OAuth2.0是一个关于授权的开放网络协议. 该协议在第三方应用与服务提供平台之间设置了一个授权层.第三方应用需要服务资源时,并不是直接使用用户帐 ...

随机推荐

  1. heartbeat.go

    body: %s", resp.StatusCode, body)     }     return nil }

  2. InfluxDB介绍

    InfluxDB介绍 InfluxDB用Go语言编写的一个开源分布式时序.事件和指标数据库,和传统是数据库相比有不少不同的地方. 类似的数据库有Elasticsearch.Graphite等. 特点 ...

  3. 【最小生成树】Bzoj1601[Usaco2008 Oct]灌水

    Description Farmer John已经决定把水灌到他的n(1<=n<=300)块农田,农田被数字1到n标记.把一块土地进行灌水有两种方法,从其他农田饮水,或者这块土地建造水库. ...

  4. Java基础-抽象类和接口

    抽象类与接口是Java语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予java强大的面向对象的能力.他们两者之间对抽象概念的支持有很大的相似,甚至可以互换,但是也有区别. 抽象定义: 抽象 ...

  5. UR机械臂运动学正逆解方法

    最近几个月因为工作接触到了机械臂的项目,突然对机械臂运动方法产生了兴趣,也就是如何控制机械臂的位置和姿态.借用一张网上的图片,应该是ur5的尺寸.我用到的是ur3机械臂,除了尺寸不一样,各关节结构和初 ...

  6. Docker 集群

    1.  理解swarm swarm(译:集群) 一个swarm是一组运行着Docker的机器,它们一起加入到一个集群.swarm中的机器既可以是物理机,也可以是虚拟机.在加入到一个swarm后,每台机 ...

  7. 【转】mip-semi-fixed 走走又停停

    写在前面 MIP 中悬浮元素的特殊情况 其实组件上线已经有一段时间了,最开始看到这个需求是站长提交了一个这中功能的组件过来,不过看过代码立刻就想到了 MIP 页面的特殊性:从结果页打开的 MIP 页面 ...

  8. 使用bootstrap table 数据绑定

    1.最近一直在用bootstrap table 这个前端框架做项目,下面是使用bootstrap table 的一些总结 这个使用.Net 中MVC做的: 2.这个是基本的boostrap table ...

  9. JavaSE:关键字(全)

    访问控制: private 访问控制方式:私有的 protected 访问控制方式:受保护的 public 访问控制方式:公共的 类.方法和变量修饰符: abstract 声明抽象,表明类或者成员方法 ...

  10. Java 学习笔记 Junit4单元测试使用

    Junit使用 1.导入Junit包 到官网下载个Junit4.12.jar文件,放在lib目录 或者在类的空白处打@Test,之后按下alt+enter,选择添加Junit4依赖 之后就会弹出一个窗 ...