SpringSecurity实现用户名密码登录(Token)

传统的应用是将Session放在应用服务器上,而将生成的JSESSIONID放在用户浏览器的Cookie中,而这种模式在前后端分离中就会出现以下问题
1,开发繁琐。
2,安全性和客户体验差
3,有些前端技术不支持Cookie,如微信小程序
这种情况下,前后端之间使用Token(令牌)进行通信就完美的解决上面的问题。

⒈添加pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
⒉编写AuthenticationSuccessHandler的实现
package cn.coreqi.handler; import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.StringUtils;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Base64; @Component("coreqiAuthenticationSuccessHandler")
public class CoreqiAuthenticationSuccessHandler implements AuthenticationSuccessHandler { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired
private ClientDetailsService clientDetailsService; @Autowired
private AuthorizationServerTokenServices authorizationServerTokenServices; @Autowired
private ObjectMapper objectMapper; //将对象转换为Json的工具类,SpringMVC在启动的时候会自动为我们注册ObjectMapper /**
* @param request 不知道
* @param response 不知道
* @param authentication Authentication接口是SpringSecurity的一个核心接口,它的作用是封装我们的认证信息,包含认证请求中的一些信息,包括认证请求的ip,Session是什么,以及认证用户的信息等等。
* @throws IOException
* @throws ServletException
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//1.从请求参数中拿到ClientId
String header = request.getHeader("Authorization");
if (header == null && !header.toLowerCase().startsWith("basic ")) {
throw new UnapprovedClientAuthenticationException("请求头中无client信息!");
}
String[] tokens = this.extractAndDecodeHeader(header, request);
assert tokens.length == 2; String clientId = tokens[0];
String clientSecret = tokens[1]; //2.通过ClientId拿到ClientDetails
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
if(clientDetails == null){
throw new UnapprovedClientAuthenticationException("clientId对应的配置信息不存在:" + clientId);
}else if(!StringUtils.equals(clientDetails.getClientSecret(),clientSecret)){
throw new UnapprovedClientAuthenticationException("clientSecret不匹配:" + clientId);
}
//3.创建TokenRequest
TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP,clientId,clientDetails.getScope(),"custom"); //4.构建OAuth2Request
OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails); //5.构建OAuth2Authentication
OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request,authentication); //6.构建OAuth2AccessToken
OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(oAuth2Authentication); //7.将生成的Token返回给请求
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(token));
} /**
* 从请求头中解析用户名密码
* @param header
* @param request
* @return
* @throws IOException
*/
private String[] extractAndDecodeHeader(String header, HttpServletRequest request) throws IOException {
byte[] base64Token = header.substring(6).getBytes("UTF-8"); byte[] decoded;
try {
decoded = Base64.getDecoder().decode(base64Token);
} catch (IllegalArgumentException var7) {
throw new BadCredentialsException("Failed to decode basic authentication token");
} String token = new String(decoded, "UTF-8");
int delim = token.indexOf(":");
if (delim == -1) {
throw new BadCredentialsException("Invalid basic authentication token");
} else {
return new String[]{token.substring(0, delim), token.substring(delim + 1)};
}
} }
⒊配置Security
package cn.coreqi.config; import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; @EnableWebSecurity
public class CoreqiWebSecurityConfig extends WebSecurityConfigurerAdapter { @Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
} @Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/oauth/token","/login").permitAll()
.anyRequest().authenticated() //任何请求都需要身份认证
.and().csrf().disable(); //禁用CSRF
} @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("fanqi").password("admin").roles("admin");
} @Bean
public PasswordEncoder passwordEncoder()
{
return NoOpPasswordEncoder.getInstance();
}
}
⒋配置OAuth2
package cn.coreqi.config; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; @Configuration
@EnableAuthorizationServer //开启认证服务器
public class CoreqiAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager; @Autowired
private AuthenticationConfiguration authenticationConfiguration; /**
* password模式需要提供一个AuthenticationManager到AuthorizationServerEndpointsConfigurer
* @param authorizationServerEndpointsConfigurer
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer authorizationServerEndpointsConfigurer) throws Exception {
authorizationServerEndpointsConfigurer.authenticationManager(authenticationConfiguration.getAuthenticationManager());
} @Override
public void configure(ClientDetailsServiceConfigurer clientDetailsServiceConfigurer) throws Exception {
clientDetailsServiceConfigurer.inMemory()
.withClient("coreqi")
.secret("coreqiSecret")
.redirectUris("https://www.baidu.com")
.scopes("ALL")
.authorities("COREQI_READ")
.authorizedGrantTypes("authorization_code","password");
} }
⒌配置资源服务器
package cn.coreqi.config; import cn.coreqi.handler.CoreqiAuthenticationSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; @Configuration
@EnableResourceServer //开启资源服务器
public class CoreqiResourceServerConfig extends ResourceServerConfigurerAdapter { @Autowired
private CoreqiAuthenticationSuccessHandler coreqiAuthenticationSuccessHandler; @Override
public void configure(HttpSecurity http) throws Exception {
http.formLogin()
.successHandler(coreqiAuthenticationSuccessHandler)
.and()
.authorizeRequests()
.antMatchers("/oauth/token","/login").permitAll()
.anyRequest().authenticated() //任何请求都需要身份认证
.and()
.csrf()
.disable(); //禁用CSRF
} }
⒍测试


SpringSecurity实现用户名密码登录(Token)的更多相关文章
- Python用户名密码登录系统(MD5加密并存入文件,三次输入错误将被锁定)及对字符串进行凯撒密码加解密操作
# -*- coding: gb2312 -*- #用户名密码登录系统(MD5加密并存入文件)及对字符串进行凯撒密码加解密操作 #作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.co ...
- pyhton学习,day1作业,用户名密码登录模块
要求,通过用户名密码登录,登录错误3次,锁定用户名 # coding=utf-8 # Author: RyAn Bi import os, sys #调用系统自己的库 accounts_file = ...
- cassandra根据用户名密码登录cqlsh
修改conf目录下cassandra.yaml文件 authenticator: PasswordAuthenticator //将authenticator修改为PasswordAuthentic ...
- 用户名密码登录小程序及input与raw_input区别。
一.此次程序需要实现: 1.设定固定的用户名密码 2.用户名密码输入正确打印登录正确信息 3.仅仅运行三次登录 二.本次使用的python版本为: Windows下版本号: C:\Users\dais ...
- Spring Security之用户名+密码登录
自定义用户认证逻辑 处理用户信息获取逻辑 实现UserDetailsService接口 @Service public class MyUserDetailsService implements Us ...
- 【Python练习】文件引用用户名密码登录系统
一.通过txt文件引入用户名密码 1 #coding=utf-8 from selenium import webdriver #from selenium.common.exceptions imp ...
- 【转】IIS网站浏览时提示需要用户名密码登录-解决方法
打开iis,站点右键----属性----目录安全性----编辑----允许匿名访问钩选 IIS连接127.0.0.1要输入用户名密码的解决办法原因很多,请尝试以下操作: 1.查看网站属性——文档看看启 ...
- MongoDB 用户名密码登录
Mongodb enable authentication MongoDB 默认直接连接,无须身份验证,如果当前机器可以公网访问,且不注意Mongodb 端口(默认 27017)的开放状态,那么Mon ...
- 亚马逊AWS CentOS7(linux)改为用户名密码登录
1.进入AWS系统 略 系统为:centos 7 fox.风 2.设置ROOT密码 sudo passwd root 1 3.修改配置文件 sudo vim /etc/ssh/sshd_config ...
随机推荐
- 浏览器console打印定义样式
%指令 c:表示样式(css) 其他的大家查资料吧 console.log("%c dsajfklsdjljfdskl", "color:red;font-size:50 ...
- 用jQuery写的轮播图
效果图: GitHub地址:https://github.com/123456abcdefg/Javascript 大家可以下载源码查看. 与前一篇写的轮播图实现的效果一致,这个是用jQuery写的, ...
- python3 rrdtool 使用
源自 python自动化运维:技术与最佳实践 并做略微修改 安装 yum install python-rrdtoolyum install rrdtool-devel #因为采集用了psutil模块 ...
- JAVA核心技术I---JAVA基础知识(数据类型)
一:基本类型 –boolean 布尔 –byte 字节 –short/int/long 短整数/整数/长整数 –float/double 浮点数 –char 字符 (一)boolean 只有true, ...
- vue中v-show与v-if的区别
v-show 手段:通过设置DOM元素的display样式属性控制显隐: 编译过程:v-show只是简单的基于css切换: 编译条件:v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存 ...
- Ubuntu 18.04 设置开机启动脚本 rc.local systemd
ubuntu18.04不再使用initd管理系统,改用systemd. ubuntu-18.04不能像ubuntu14一样通过编辑rc.local来设置开机启动脚本,通过下列简单设置后,可以使rc.l ...
- 加密PDF文件的打印问题
工作中遇到网上下载的PDF文件加密,并且不能打印 解决方法: 1.解密: 去网站下载解密软件,1M左右:http://www.onlinedown.net/soft/19939.htm 直接解压,运行 ...
- 【1】【leetcode-115】 不同的子序列 distinct-subsequences
不同的子序列 distinct-subsequences(hard) (忘了,典型) 给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数. 一个字符串的一个子序列是指,通过删 ...
- HDU - 6314 Matrix(广义容斥原理)
http://acm.hdu.edu.cn/showproblem.php?pid=6314 题意 对于n*m的方格,每个格子只能涂两种颜色,问至少有A列和B行都为黑色的方案数是多少. 分析 参考ht ...
- POJ - 2057 The Lost House(树形DP+贪心)
https://vjudge.net/problem/POJ-2057 题意 有一只蜗牛爬上某个树枝末睡着之后从树上掉下来,发现后面的"房子"却丢在了树上面,.现在这只蜗牛要求寻找 ...