⒈认证服务器

  1.添加pom依赖   

         <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.1.2.RELEASE</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>

  2.配置文件相关配置  

 server.port=10086
server.servlet.context-path=/server

  3.Security配置

 package cn.coreqi.ssoserver.config;

 import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; @EnableWebSecurity
public class SsoWebSecurityConfig extends WebSecurityConfigurerAdapter { @Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
} @Qualifier("ssoUserDetailsService")
@Autowired
private UserDetailsService userDetailsService; @Bean
public PasswordEncoder passwordEncoder()
{
//return NoOpPasswordEncoder.getInstance();
//return new BCryptPasswordEncoder();
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
} @Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.and()
.authorizeRequests()
.antMatchers("/oauth/*","/login/*").permitAll()
.anyRequest().authenticated() //任何请求都需要身份认证
.and().csrf().disable(); //禁用CSRF
} @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.inMemoryAuthentication()
// .withUser("fanqi").password("admin").roles("admin");
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
}

  ⒋用户登录逻辑

  

 package cn.coreqi.ssoserver.service;

 import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
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.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component; @Component
public class SsoUserDetailsService implements UserDetailsService { @Autowired
private PasswordEncoder passwordEncoder; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return new User(username,passwordEncoder.encode("admin"),
AuthorityUtils.commaSeparatedStringToAuthorityList("ADMIN"));
}
}

  5.认证服务器配置

 package cn.coreqi.ssoserver.config;

 import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
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;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; @Configuration
@EnableAuthorizationServer //声明当前应用为认证服务器
public class SsoAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired
private AuthenticationManager authenticationManagerBean; @Autowired
private PasswordEncoder passwordEncoder; /**
* Token生成过程处理
* @return
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(){
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
accessTokenConverter.setSigningKey("fanqi"); //Token签名用的密钥
//发出去的令牌需要密钥签名,验令牌的时候也需要令牌来验签,如果他人获知了我们的密钥
//就可以用我们的密钥来签发我们的JWT令牌,JWT唯一的安全性就是密钥
//别人用我们的密钥来签发我们的JWT令牌就可以随意进入我们的系统
return accessTokenConverter;
} @Bean
public TokenStore jwtTokenStore(){
return new JwtTokenStore(jwtAccessTokenConverter());
} /**
* 针对端点的配置
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(jwtTokenStore())
.accessTokenConverter(jwtAccessTokenConverter())
.authenticationManager(authenticationManagerBean);
} /**
* 配置当前认证服务器可以给那些应用发令牌
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory()
.withClient("coreqi1")
.secret(passwordEncoder.encode("coreqisecret1"))
.authorizedGrantTypes("authorization_code","refresh_token")
.redirectUris("http://localhost:10010/client1/login","http://127.0.0.1:10010/client1/login")
.scopes("all")
.and()
.withClient("coreqi2")
.secret(passwordEncoder.encode("coreqisecret2"))
.authorizedGrantTypes("authorization_code","refresh_token")
.redirectUris("http://localhost:10000/client2/login","http://127.0.0.1:10000/client2/login")
.scopes("all");
} /**
* 针对安全性有关的配置
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.tokenKeyAccess("isAuthenticated()"); //访问认证服务器的tokenKey(Token签名密钥)时需要身份认证
}
}

  6.覆写登录授权页面,直接跳过

 package cn.coreqi.ssoserver.controller;

 import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.HtmlUtils; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Iterator;
import java.util.Map; /**
* 登录完不授权直接进入网站
* 授权的页面根据OAuth协议是无法直接跳过去的
* 因此,我们模仿WhitelabelApprovalEndpoint类,在表单逻辑处直接提交
*/
@RestController
@SessionAttributes({"authorizationRequest"})
public class SsoApprovalEndpoint {
@RequestMapping({"/oauth/confirm_access"})
public ModelAndView getAccessConfirmation(Map<String, Object> model, HttpServletRequest request) throws Exception {
final String approvalContent = this.createTemplate(model, request);
if (request.getAttribute("_csrf") != null) {
model.put("_csrf", request.getAttribute("_csrf"));
} View approvalView = new View() {
public String getContentType() {
return "text/html";
} public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
response.setContentType(this.getContentType());
response.getWriter().append(approvalContent);
}
};
return new ModelAndView(approvalView, model);
} protected String createTemplate(Map<String, Object> model, HttpServletRequest request) {
AuthorizationRequest authorizationRequest = (AuthorizationRequest)model.get("authorizationRequest");
String clientId = authorizationRequest.getClientId();
StringBuilder builder = new StringBuilder();
builder.append("<html><body><div style='display:none'><h1>OAuth Approval</h1>");
builder.append("<p>Do you authorize \"").append(HtmlUtils.htmlEscape(clientId));
builder.append("\" to access your protected resources?</p>");
builder.append("<form id=\"confirmationForm\" name=\"confirmationForm\" action=\"");
String requestPath = ServletUriComponentsBuilder.fromContextPath(request).build().getPath();
if (requestPath == null) {
requestPath = "";
} builder.append(requestPath).append("/oauth/authorize\" method=\"post\">");
builder.append("<input name=\"user_oauth_approval\" value=\"true\" type=\"hidden\"/>");
String csrfTemplate = null;
CsrfToken csrfToken = (CsrfToken)((CsrfToken)(model.containsKey("_csrf") ? model.get("_csrf") : request.getAttribute("_csrf")));
if (csrfToken != null) {
csrfTemplate = "<input type=\"hidden\" name=\"" + HtmlUtils.htmlEscape(csrfToken.getParameterName()) + "\" value=\"" + HtmlUtils.htmlEscape(csrfToken.getToken()) + "\" />";
} if (csrfTemplate != null) {
builder.append(csrfTemplate);
} String authorizeInputTemplate = "<label><input name=\"authorize\" value=\"Authorize\" type=\"submit\"/></label></form>";
if (!model.containsKey("scopes") && request.getAttribute("scopes") == null) {
builder.append(authorizeInputTemplate);
builder.append("<form id=\"denialForm\" name=\"denialForm\" action=\"");
builder.append(requestPath).append("/oauth/authorize\" method=\"post\">");
builder.append("<input name=\"user_oauth_approval\" value=\"false\" type=\"hidden\"/>");
if (csrfTemplate != null) {
builder.append(csrfTemplate);
} builder.append("<label><input name=\"deny\" value=\"Deny\" type=\"submit\"/></label></form>");
} else {
builder.append(this.createScopes(model, request));
builder.append(authorizeInputTemplate);
} builder.append("</div><script>document.getElementById('confirmationForm').submit()</script></body></html>");
return builder.toString();
} private CharSequence createScopes(Map<String, Object> model, HttpServletRequest request) {
StringBuilder builder = new StringBuilder("<ul>");
Map<String, String> scopes = (Map)((Map)(model.containsKey("scopes") ? model.get("scopes") : request.getAttribute("scopes")));
Iterator var5 = scopes.keySet().iterator(); while(var5.hasNext()) {
String scope = (String)var5.next();
String approved = "true".equals(scopes.get(scope)) ? " checked" : "";
String denied = !"true".equals(scopes.get(scope)) ? " checked" : "";
scope = HtmlUtils.htmlEscape(scope);
builder.append("<li><div class=\"form-group\">");
builder.append(scope).append(": <input type=\"radio\" name=\"");
builder.append(scope).append("\" value=\"true\"").append(approved).append(">Approve</input> ");
builder.append("<input type=\"radio\" name=\"").append(scope).append("\" value=\"false\"");
builder.append(denied).append(">Deny</input></div></li>");
} builder.append("</ul>");
return builder.toString();
} }

⒉应用A

  1.pom依赖

    

         <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.1.2.RELEASE</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>

  2.配置文件相关配置

 server.port=10010
server.servlet.context-path=/client1
security.oauth2.client.client-id=coreqi1
security.oauth2.client.client-secret=coreqisecret1
security.oauth2.client.scope=all
security.oauth2.client.user-authorization-uri=http://127.0.0.1:10086/server/oauth/authorize
security.oauth2.client.access-token-uri=http://127.0.0.1:10086/server/oauth/token
security.oauth2.resource.jwt.key-uri=http://127.0.0.1:10086/server/oauth/token_key

  3.主程序类添加@EnableOAuth2Sso注解使之生效

 package cn.coreqi;

 import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; @SpringBootApplication
@EnableOAuth2Sso //使sso生效
public class SsoClient1Application { public static void main(String[] args) {
SpringApplication.run(SsoClient1Application.class, args);
} }

  4.编写Action接口用于查看授权信息

 package cn.coreqi.sso_client1.controller;

 import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
@RequestMapping("/user")
public class UserController { @GetMapping
public Authentication user(Authentication user){
return user;
}
}

  5.编写resources/static/index.html文件,用于跳转测试

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SSO Client1</title>
</head>
<body>
<h1> SSO Demo Client1</h1>
<a href="http://127.0.0.1:10000/client2/index.html">访问Client2</a>
</body>
</html>

⒊应用B

  1.添加pom依赖

         <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.1.2.RELEASE</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>

  2.配置文件相关配置

 server.port=10000
server.servlet.context-path=/client2
security.oauth2.client.client-id=coreqi2
security.oauth2.client.client-secret=coreqisecret2
security.oauth2.client.scope=all
security.oauth2.client.user-authorization-uri=http://127.0.0.1:10086/server/oauth/authorize
security.oauth2.client.access-token-uri=http://127.0.0.1:10086/server/oauth/token
security.oauth2.resource.jwt.key-uri=http://127.0.0.1:10086/server/oauth/token_key

  3.主程序类添加@EnableOAuth2Sso注解使之生效

 package cn.coreqi;

 import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; @SpringBootApplication
@EnableOAuth2Sso //使sso生效
public class SsoClient2Application { public static void main(String[] args) {
SpringApplication.run(SsoClient2Application.class, args);
} }

  4.编写Action接口用于查看授权信息

 package cn.coreqi.sso_client2.controller;

 import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
@RequestMapping("/user")
public class UserController { @GetMapping
public Authentication user(Authentication user){
return user;
}
}

  5.编写resources/static/index.html文件,用于跳转测试

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SSO Client2</title>
</head>
<body>
<h1> SSO Demo Client2</h1>
<a href="http://127.0.0.1:10010/client1/index.html">访问Client1</a>
</body>
</html>

SpringSecurityOAuth使用JWT Token实现SSO单点登录的更多相关文章

  1. 170810、spring+springmvc+Interceptor+jwt+redis实现sso单点登录

    在分布式环境中,如何支持PC.APP(ios.android)等多端的会话共享,这也是所有公司都需要的解决方案,用传统的session方式来解决,我想已经out了,我们是否可以找一个通用的方案,比如用 ...

  2. 使用JWT+RSA完成SSO单点登录

    无状态登录原理 1.1.什么是有状态? 有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session. 例如登录:用户登 ...

  3. Spring Cloud云架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)

    上一篇我根据框架中OAuth2.0的使用总结,画了SSO单点登录之OAuth2.0 登出流程,今天我们看一下根据用户token获取yoghurt信息的流程: /** * 根据token获取用户信息 * ...

  4. Spring Security OAuth2 SSO 单点登录

    基于 Spring Security OAuth2 SSO 单点登录系统 SSO简介 单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自 ...

  5. SSO单点登录的发展由来以及实现原理【转】

    单点登录以及权限,在很早之前都有写过,不过都比较简单,今天就具体说一下,以及下一步要做的 1.web单系统应用 早期我们开发web应用都是所有的包放在一起打成一个war包放入tomcat容器来运行的, ...

  6. sso单点登录系统

    sso单点登录概念 1.一处登录,处处登录.会单独做一个单点登录系统,只负责颁发token和验证token,和页面登录功能. 2.通过在浏览器cookie中放入token,和在redis中对应toke ...

  7. 使用 JSONP 实现简单的 SSO 单点登录

    SSO 即 Single Sign On(单点登录).  一.二级域名之间的单点登录 不需要用到JSONP 或者 p3p 协议,直接使用 COOKIE 就行了,因为顶级域名相同就能实现 COOKIE ...

  8. [sso] 单点登录认证流程

    一.流程说明 第一步:访问cas过滤链接ssoLogin,拼凑定向到 CAS_SERVER 获取ticket的URL 第二步:CAS_SERVER校验用户信息,生成Ticket 第三步:重新定向到访问 ...

  9. php sso单点登录原理阐述

    原理:就是用户登录了单点登录系统(sso)之后,就可以免登录形式进入相关系统: 实现: 点击登录跳转到SSO登录页面并带上当前应用的callback地址 登录成功后生成COOKIE并将COOKIE传给 ...

随机推荐

  1. Python对象的创建和赋值

    创建类 类的定义以关键字class开头,之后跟着一个名字(用户定义)来标识这个类,并且以冒号结尾.类的内容以缩进(4个空格)表示,如下例的pass表示什么事情也不做. Python命名规则(以字母或者 ...

  2. Burrow 服务的安装部署

    Burrow 服务的安装部署 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 最近协助开发的同时帮忙把10个topic的数据使用5个topic的来工作.结果发现数据flume在手机数 ...

  3. Django中的ORM框架使用小技巧

      Django中的ORM框架使用小技巧 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任. Django对各个数据提供了很好的支持,包括PostgreSQL,MySQL,SQLite ...

  4. MyBatis-parameterType 取出入参值

    SQL 映射文件的几种入参情况 一.单个基本类型参数 public MyUser selectMyUser(Integer id); <!-- #{参数名或任意名}:取出参数值 --> & ...

  5. C++回顾day02---<对象构造和析构,外加友元函数>

    一:若没有显示写构造函数,默认会有一个默认构造函数(无参),若自己构造后,不会存在这个默认构造函数 二:类成员若是有const修饰,必须在对象初始化的时候,为该类成员赋值(或者一开始就定死,同C中) ...

  6. 使用rvm安装与切换Ruby

    列出已知的 Ruby 版本 rvm list known安装一个 Ruby 版本 rvm install 2.3.1 --disable-binary这里安装了最新的 2.2.0, rvm list ...

  7. c++进阶学习

    以后可能要做c++开发了..记录要看的书和可能用的技术,让自己有个学习的方向... 1. 语言基础 2. 算法与数据结构基础 3. 多线程开发基础  4. 数据库  5. 网络编程 6. 内存数据库技 ...

  8. Golang入门教程(十三)延迟函数defer详解

    前言 大家都知道go语言的defer功能很强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.Go 语言中延迟函数 defer 充当着 try...catch 的重任,使用起来也非常简便,然而在 ...

  9. Vuex笔记

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 Vuex - 状态管理器,可以管理你的数据状态(类似于 React的 Redux) 一个 Vuex 应用的核心是 store(仓库,一个 ...

  10. Set接口HashSet实现类

    java.util.Set接口 extends Collection接口 Set特点: 1.不允许有重复的元素 2.没有索引,没有带索引的方法,也不能使用普通的for遍历 java.util.Hash ...