security和oauth2.0的整合

之前已经介绍过security的相关的介绍,现在所需要做的就是security和oauth2.0的整合,在原有的基础上我们加上一些相关的代码;代码实现如下:

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>urity.demo</groupId>
<artifactId>security-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!--以下两项需要如果不配置,解析themleaft 会有问题-->
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.0.5</thymeleaf-layout-dialect.version>
</properties> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency> <dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>Brussels-SR9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency> <!--mybatis与mysql-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--druid依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.25</version>
</dependency>
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> <!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency> <!--jasypt加解密-->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>1.14</version>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency> <!--oauth2.0-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency> <dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency> <dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
</dependency> <!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency> <!--session集群管理-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
</dependency> <dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency> <!--zipkin-->
<!-- <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>--> <!--eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> <!--添加static和templates的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency> <!--config-->
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-starter-config</artifactId>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-starter-bus-amqp</artifactId>-->
<!--</dependency>-->
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

这里我们需要注意导入依赖的版本,版本过高可能会存在一些未知的问题:

AuthorizationServerConfiguration核心类:

package urity.demo.oauth2;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
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.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import urity.demo.service.RedisAuthenticationCodeServices; import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map; @Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { @Value("${resource.id:spring-boot-application}")
private String resourceId; @Value("${access_token.validity_period:36000}")
private int accessTokenValiditySeconds = 36000; //认证管理 很重要 如果security版本高可能会出坑哦
@Resource
private AuthenticationManager authenticationManager; @Resource
private RedisAuthenticationCodeServices redisAuthenticationCodeServices; //定义令牌端点上的安全约束。
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')");
oauthServer.checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')"); } //将ClientDetailsServiceConfigurer(从您的回调AuthorizationServerConfigurer)可以用来在内存或JDBC实现客户的细节服务来定义的。客户端的重要属性是
//clientId:(必填)客户端ID。
//secret:(可信客户端需要)客户机密码(如果有)。
//scope:客户受限的范围。如果范围未定义或为空(默认值),客户端不受范围限制。
//authorizedGrantTypes:授予客户端使用授权的类型。默认值为空。
//authorities授予客户的授权机构(普通的Spring Security权威机构)。
//客户端的详细信息可以通过直接访问底层商店(例如,在数据库表中JdbcClientDetailsService)或通过ClientDetailsManager接口(这两种实现ClientDetailsService也实现)来更新运行的应用程序。
//注意:JDBC服务的架构未与库一起打包(因为在实践中可能需要使用太多变体)
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception { //默认值InMemoryTokenStore对于单个服务器是完全正常的(即,在发生故障的情况下,低流量和热备份备份服务器)。大多数项目可以从这里开始,也可以在开发模式下运行,以便轻松启动没有依赖关系的服务器。
//这JdbcTokenStore是同一件事的JDBC版本,它将令牌数据存储在关系数据库中。如果您可以在服务器之间共享数据库,则可以使用JDBC版本,如果只有一个,则扩展同一服务器的实例,或者如果有多个组件,则授权和资源服务器。要使用JdbcTokenStore你需要“spring-jdbc”的类路径。 clients.inMemory()
//client Id
.withClient("normal-app")
.authorizedGrantTypes("authorization_code", "implicit")
.authorities("ROLE_CLIENT")
.scopes("read","write")
.resourceIds(resourceId)
.accessTokenValiditySeconds(accessTokenValiditySeconds)
.and()
.withClient("trusted-app")
.authorizedGrantTypes("client_credentials", "password")
.authorities("ROLE_TRUSTED_CLIENT")
.scopes("read", "write")
.resourceIds(resourceId)
.accessTokenValiditySeconds(accessTokenValiditySeconds)
.secret("secret"); } //AuthorizationEndpoint可以通过以下方式配置支持的授权类型AuthorizationServerEndpointsConfigurer。默认情况下,所有授权类型均受支持,除了密码(有关如何切换它的详细信息,请参见下文)。以下属性会影响授权类型:
//authenticationManager:通过注入密码授权被打开AuthenticationManager。
//userDetailsService:如果您注入UserDetailsService或者全局配置(例如a GlobalAuthenticationManagerConfigurer),则刷新令牌授权将包含对用户详细信息的检查,以确保该帐户仍然活动
//authorizationCodeServices:定义AuthorizationCodeServices授权代码授权的授权代码服务(实例)。
//implicitGrantService:在批准期间管理状态。
//tokenGranter:(TokenGranter完全控制授予和忽略上述其他属性)
//在XML授予类型中包含作为子元素authorization-server。 /**
* /oauth/authorize您可以从该请求中获取所有数据,
* 然后根据需要进行渲染,
* 然后所有用户需要执行的操作都是回复有关批准或拒绝授权的信息。
* 请求参数直接传递给您UserApprovalHandler,
* AuthorizationEndpoint所以您可以随便解释数据
*
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(this.authenticationManager);
endpoints.accessTokenConverter(accessTokenConverter());//jwt
endpoints.tokenStore(tokenStore()); //授权码存储
endpoints.authorizationCodeServices(redisAuthenticationCodeServices); } @Bean
public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter() {
/**
* 重写增强token的方法
* 自定义返回相应的信息
*
*/ @Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { String userName = authentication.getUserAuthentication().getName();
// 与登录时候放进去的UserDetail实现类一直查看link{SecurityConfiguration}
User user = (User) authentication.getUserAuthentication().getPrincipal();
/** 自定义一些token属性 ***/
final Map<String, Object> additionalInformation = new HashMap<>();
additionalInformation.put("userName", userName);
additionalInformation.put("roles", user.getAuthorities());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);
OAuth2AccessToken enhancedToken = super.enhance(accessToken, authentication);
return enhancedToken;
} };
// 测试用,资源服务使用相同的字符达到一个对称加密的效果,生产时候使用RSA非对称加密方式
accessTokenConverter.setSigningKey("123");
return accessTokenConverter; } @Bean
public TokenStore tokenStore() { TokenStore tokenStore = new JwtTokenStore(accessTokenConverter()); return tokenStore;
} }

RedisAuthenticationCodeServices:

我们把授权码存在了redis中:

package urity.demo.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.code.RandomValueAuthorizationCodeServices;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.security.oauth2.common.util.SerializationUtils; //自定义为使用redis存储授权码
@Service
@Slf4j
public class RedisAuthenticationCodeServices extends RandomValueAuthorizationCodeServices { private static final String AUTH_CODE_KEY = "my_code"; private RedisConnectionFactory connectionFactory; public RedisAuthenticationCodeServices(RedisConnectionFactory connectionFactory) {
Assert.notNull(connectionFactory, "RedisConnectionFactory required");
this.connectionFactory = connectionFactory;
} private RedisConnection getConnection() { return connectionFactory.getConnection();
} //redis存储
@Override
protected void store(String code, OAuth2Authentication authentication) { RedisConnection conn = getConnection(); try { conn.hSet(AUTH_CODE_KEY.getBytes("utf-8"), code.getBytes("utf-8"), SerializationUtils.serialize(authentication)
);
} catch (Exception e) { conn.close();
} } @Override
protected OAuth2Authentication remove(String code) {
RedisConnection conn = getConnection();
try { OAuth2Authentication authentication = null; try {
authentication = SerializationUtils
.deserialize(conn.hGet(AUTH_CODE_KEY.getBytes("utf-8"),
code.getBytes("utf-8"))); } catch (Exception e) {
e.printStackTrace(); } if (authentication != null) {
conn.hDel(AUTH_CODE_KEY.getBytes("utf-8"),
code.getBytes("utf-8"));
} return authentication;
} catch (Exception e) {
e.printStackTrace();
} finally {
conn.close();
}
return null;
}
}

ResourceController:

package urity.demo.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; /***
* 受保护的资源服务
* @author leftso
*
*/
@RestController
@RequestMapping("/resources")
public class ResourceController {
/**
* 需要用户角色权限
* @return
*/
@PreAuthorize("hasRole('ROLE_USER')")
@RequestMapping(value="user", method=RequestMethod.GET)
public String helloUser() {
return "hello user";
}
/**
* 需要管理角色权限
*
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@RequestMapping(value="admin", method=RequestMethod.GET)
public String helloAdmin() {
return "hello admin";
}
/**
* 需要客户端权限
*
* @return
*/
@PreAuthorize("hasRole('ROLE_CLIENT')")
@RequestMapping(value="client", method=RequestMethod.GET)
public String helloClient() {
return "hello user authenticated by normal client";
}
/**
* 需要受信任的客户端权限
*
* @return
*/
@PreAuthorize("hasRole('ROLE_TRUSTED_CLIENT')")
@RequestMapping(value="trusted_client", method=RequestMethod.GET)
public String helloTrustedClient() {
return "hello user authenticated by trusted client";
} @RequestMapping(value="principal", method=RequestMethod.GET)
public Object getPrincipal() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return principal;
} @RequestMapping(value="roles", method=RequestMethod.GET)
public Object getRoles() {
return SecurityContextHolder.getContext().getAuthentication().getAuthorities();
} }

application.xml:

server:
port: 8787
spring:
redis:
host: 127.0.0.1
port: 6379
# password: redis
database: 0
datasource:
url: jdbc:mysql://localhost:3306/test
username: ***
password: ***
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
initialSize: 5
minIdle: 5
maxActive: 30
maxWait: 10000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMills: 300000
session:
store-type: none
other:
security:
oauth2:
signKey: oauth

security和oauth2.0的整合的更多相关文章

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

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

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

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

  3. Spring Cloud(6):保护微服务(Security) - OAuth2.0

    OAuth2是一个授权(Authorization)协议.我们要和Spring Security的认证(Authentication)区别开来,认证(Authentication)证明的你是不是这个人 ...

  4. SpringBootSecurity学习(14)前后端分离版之 OAuth2.0介绍

    登录总结 前面基本介绍了security的常规用法,同时介绍了JWT和它的一个简单实现,基本上开发中遇到的登录问题都能解决了,即使在分布式开发,或者微服务开发中实现登录也基本没有问题了.securit ...

  5. 整合spring cloud云架构 - SSO单点登录之OAuth2.0登录认证(1)

    之前写了很多关于spring cloud的文章,今天我们对OAuth2.0的整合方式做一下笔记,首先我从网上找了一些关于OAuth2.0的一些基础知识点,帮助大家回顾一下知识点: 一.oauth中的角 ...

  6. Spring Security OAuth2.0 - AuthorizationServer和ResourceServer分离

    <Spring Security实现OAuth2.0授权服务 - 基础版>和<Spring Security实现OAuth2.0授权服务 - 进阶版>两篇文章中介绍如何搭建OA ...

  7. Spring Cloud Security OAuth2.0 认证授权系列(一) 基础概念

    世界上最快的捷径,就是脚踏实地,本文已收录[架构技术专栏]关注这个喜欢分享的地方. 前序 最近想搞下基于Spring Cloud的认证授权平台,总体想法是可以对服务间授权,想做一个基于Agent 的无 ...

  8. Spring Cloud Zuul 网关使用与 OAuth2.0 认证授权服务

    API 网关的出现的原因是微服务架构的出现,不同的微服务一般会有不同的服务地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题: 客户端会 ...

  9. Spring Cloud云架构 - SSO单点登录之OAuth2.0登录认证(1)

    今天我们对OAuth2.0的整合方式做一下笔记,首先我从网上找了一些关于OAuth2.0的一些基础知识点,帮助大家回顾一下知识点: 一.oauth中的角色 client:调用资源服务器API的应用 O ...

随机推荐

  1. 《官方资料》 例如:string 函数 、分组函数

    site:www.mysql.com SUBSTRING_INDEX ----------------------------------------------------------------- ...

  2. parseInt(string, radix)

    参数 描述 string 必需.要被解析的字符串. radix 可选.表示要解析的数字的基数.该值介于 2 ~ 36 之间. 如果省略该参数或其值为 0,则数字将以 10 为基础来解析.如果它以 “0 ...

  3. 无线破解那点事(PJ)

    有一段时间没有写博客了.只能说苦逼学生党伤不起啊,还好没挂-废话不说了,近期将会讲讲无线PJ那点事,也不是啥干货,就一些先前的笔记分享把. 0.无线网卡 想要提高破解效率,一块猛一点的USB无线网卡是 ...

  4. centos 中 mongodb 启动失败的修复

    mongodb是使用centos的yum命令安装的,整个的安装过程如下: 1. 运行 yum info mongo-10gen查看是否有mongodb源,如有跳至第3步. 2. 运行 vim /etc ...

  5. SQL Server Job

    1. SQL Server Job创建:(SQL Server 代理 - 作业)鼠标右键.新建作业. 2.[常规]选项:定义作业名称.和说明信息. 3:[步骤]选项:新建步骤 4:定义步骤名称.设置对 ...

  6. c#去除DataTable空列

    网上搜了好多,没找到能用的,自己写一个,有发现错误的给我留言. private void RemoveNULLColumns(ref DataTable data)//删除空列 { try { Dat ...

  7. Android ScrollView 去掉 scrollbar 和 阴影

    1. 在 layout 里: android:scrollbars="none" android:overScrollMode="never" 2. 代码里 / ...

  8. 解决 UnicodeEncodeError: 'ascii' codec can't encode characters in position 问题

    在开头加上 import sys reload(sys) sys.setdefaultencoding( "utf-8" ) Python自然调用ascii编码解码程序去处理字符流 ...

  9. “java.lang.NullPointerException”异常分析

    1.父类定义的某个属性,没有被子类使用,或者在子类中,又重新定义一次. 2.因为调用了一个object的方法,且此object的reference为null:比如说:String a=null; // ...

  10. [USACO17FEB]Why Did the Cow Cross the Road III P(CDQ分治)

    题意 两列$n$的排列,相同的数连边,如果一对数有交叉且差的绝对值$>k$,则$++ans$,求$ans$ 题解 可以把每一个数字看成一个三元组$(x,y,z)$,其中$x$表示在第一列的位置, ...