spring-security实现的token授权
在我的用户密码授权文章里介绍了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授权的更多相关文章
- 使用Redis作为Spring Security OAuth2的token存储
写在前边 本文对Spring Security OAuth2的token使用Redis保存,相比JWT实现的token存储,Redis可以随时吊销access_token,并且Redis响应速度很快, ...
- Spring Security实现OAuth2.0授权服务 - 进阶版
<Spring Security实现OAuth2.0授权服务 - 基础版>介绍了如何使用Spring Security实现OAuth2.0授权和资源保护,但是使用的都是Spring Sec ...
- Spring Security OAuth2.0认证授权二:搭建资源服务
在上一篇文章[Spring Security OAuth2.0认证授权一:框架搭建和认证测试](https://www.cnblogs.com/kuangdaoyizhimei/p/14250374. ...
- Spring Security OAuth2.0认证授权三:使用JWT令牌
Spring Security OAuth2.0系列文章: Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二: ...
- Spring Security OAuth2.0认证授权四:分布式系统认证授权
Spring Security OAuth2.0认证授权系列文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授 ...
- Spring Security OAuth2.0认证授权五:用户信息扩展到jwt
历史文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二:搭建资源服务 Spring Security OA ...
- Spring Security OAuth2.0认证授权六:前后端分离下的登录授权
历史文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二:搭建资源服务 Spring Security OA ...
- Spring Security OAuth 格式化 token 输出
个性化token 背景 上一篇文章<Spring Security OAuth 个性化token(一)>有提到,oauth2.0 接口默认返回的报文格式如下: { "ac ...
- 使用JWT作为Spring Security OAuth2的token存储
序 Spring Security OAuth2的demo在前几篇文章中已经讲过了,在那些模式中使用的都是RemoteTokenService调用授权服务器来校验token,返回校验通过的用户信息供上 ...
- Spring Security实现OAuth2.0授权服务 - 基础版
一.OAuth2.0协议 1.OAuth2.0概述 OAuth2.0是一个关于授权的开放网络协议. 该协议在第三方应用与服务提供平台之间设置了一个授权层.第三方应用需要服务资源时,并不是直接使用用户帐 ...
随机推荐
- Elasticsearch笔记六之中文分词器及自定义分词器
中文分词器 在lunix下执行下列命令,可以看到本来应该按照中文"北京大学"来查询结果es将其分拆为"北","京","大" ...
- BZOJ_3689_异或之_可持久化Trie+堆
BZOJ_3689_异或之_可持久化Trie+堆 Description 给定n个非负整数A[1], A[2], ……, A[n]. 对于每对(i, j)满足1 <= i < j < ...
- ArcGIS API for JavaScript 入门教程[1] 渊源
->对于萌新,你可能需要了解一下这个东西是什么 ->对于已经知道要用这个东西的开发者,你可能需要了解一下它的底层机制 不针对大牛.龟速更新ing. 转载注明出处.博客园&CSDN& ...
- Python任务调度模块 – APScheduler,实现定时任务
1.安装 pip install apscheduler 安装完毕 2. 简单任务 首先,来个最简单的例子,看看它的威力. # coding:utf-8 from apscheduler.schedu ...
- 【填坑纪事】一次用System.nanoTime()填坑System.currentTimeMills()的实例记录
JDK提供了两个方法,System.currentTimeMillis()和System.nanoTime(),这两个方法都可以用来获取表征当前时间的数值.但是如果不仔细辨别这两个方法的差别和联系,在 ...
- 安卓开发笔记(二十六):Splash实现首页快速开屏功能
我们在进行安卓开发的时候,首页开有两种方式,一种是利用handler将一个活动进行延时,时间到达之后软件则会跳转到第二个活动当中.而另一种方法则是更加常用的方法,利用splash实现首页的快速开屏,这 ...
- ASP.NET Core2.2+Quartz.Net 实现web定时任务
作为一枚后端程序狗,项目实践常遇到定时任务的工作,最容易想到的的思路就是利用Windows计划任务/wndows service程序/Crontab程序等主机方法在主机上部署定时任务程序/脚本. 但是 ...
- 腾讯云存储专家深度解读基于Ceph对象存储的混合云机制
背景 毫无疑问,乘着云计算发展的东风,Ceph已经是当今最火热的软件定义存储开源项目.如下图所示,它在同一底层平台之上可以对外提供三种存储接口,分别是文件存储.对象存储以及块存储,本文主要关注的是对象 ...
- asp.net core系列 51 Identity 授权(下)
1.6 基于资源的授权 前面二篇中,熟悉了五种授权方式(对于上篇讲的策略授权,还有IAuthorizationPolicyProvider的自定义授权策略提供程序没有讲,后面再补充).本篇讲的授权方式 ...
- Java8新特性之五:Optional
NullPointerException相信每个JAVA程序员都不陌生,是JAVA应用程序中最常见的异常.之前,Google Guava项目曾提出用Optional类来包装对象从而解决NullPoin ...