当前位置: 首页 > news >正文

网页站点什么意思汽车之家网站

网页站点什么意思,汽车之家网站,套模板做网站电话,安徽网站开发费用1.Oauth2 OAuth 2.0授权框架支持第三方支持访问有限的HTTP服务#xff0c;通过在资源所有者和HTTP服务之间进行一个批准交互来代表资源者去访问这些资源#xff0c;或者通过允许第三方应用程序以自己的名义获取访问权限。 为了方便理解#xff0c;可以想象OAuth2.0就是在用… 1.Oauth2 OAuth 2.0授权框架支持第三方支持访问有限的HTTP服务通过在资源所有者和HTTP服务之间进行一个批准交互来代表资源者去访问这些资源或者通过允许第三方应用程序以自己的名义获取访问权限。 为了方便理解可以想象OAuth2.0就是在用户资源和第三方应用之间的一个中间层它把资源和第三方应用隔开使得第三方应用无法直接访问资源从而起到保护资源的作用。 为了访问这种受保护的资源第三方应用客户端在访问的时候需要提供凭证。即需要告诉OAuth2.0你是谁你要做什么。 用户可以将用户名和密码告诉第三方应用让第三方应用直接以你的名义去访问也可以授权第三方应用去访问。 例如微信公众平台开发在微信公众平台开发过程中当我们访问某个页面页面可能弹出一个提示框应用需要获取我们的个人信息问是否允许点确认其实就是授权第三方应用获取我们在微信公众平台的个人信息这里微信网页授权就是使用的OAuth2.0。 第三方应用程序Third-party application 又称之为客户端client我们自己开发的各种客户端对我们自己的项目来说QQ、微信、支付宝等是第三方应用程序。 HTTP 服务提供商HTTP service 我们开发的项目以及 QQ、微信、支付宝、钉钉等都可以称之为“服务提供商”。 资源所有者Resource Owner 又称之为用户user拥有账号密码的人。 用户代理User Agent 用来访问资源比如浏览器代替用户去访问这些资源。 认证服务器Authorization server 即服务提供商专门用来处理认证的服务器主要就是实现登录、授权功能。 资源服务器Resource server 即服务提供商存放用户生成的资源的服务器比如电商中的商品模块、订单模块等是用来处理具体业务的服务器。 OAuth2.0协议流程描述了四种角色之间的交互过程如下图所示。 简单说OAuth 就是一种授权机制。数据的所有者告诉系统同意授权第三方应用进入系统获取这些数据。系统从而产生一个短期的进入令牌token用来代替密码供第三方应用使用。 令牌token与密码password的作用是一样的都可以进入系统但是有三点差异。 令牌是短期的到期会自动失效用户自己无法修改。密码一般长期有效用户不修改就不会发生变化。 令牌可以被数据所有者撤销会立即失效。 令牌有权限范围scope对于网络服务来说只读令牌就比读写令牌更安全。密码一般是完整权限。 上面这些设计保证了令牌既可以让第三方应用获得权限同时又随时可控不会危及系统安全。这就是 OAuth 2.0 的优点。 注意只要知道了令牌就能进入系统。系统一般不会再次确认身份所以令牌必须保密泄漏令牌与泄漏密码的后果是一样的。 这也是为什么令牌的有效期一般都设置得很短的原因。 1.1 开放平台 开放平台Open Platform在软件行业和网络中开放平台是指软件系统通过公开其应用程序编程接口API或函数function)来使外部的程序可以增加该软件系统的功能或使用该软件系统的资源而不需要更改该软件系统的源代码。 在互联网时代把网站的服务封装成一系列计算机易识别的数据接口开放出去供第三方开发者使用这种行为就叫做Open API提供开放API的平台本身就被称为开放平台。 第一种是技术性的开放例如百度、腾讯、阿里巴巴等例如阿里可以提供标准化的应用软件但是数百万形形色色的卖家对于个性化要求的软件并不是一个公司的力量可以满足的所以就把这些需求开放给众多的第三方开发者的方式。再例如google的基于Linux平台的开源手机操作系统就被认为会很快打败Nokia塞班系统。这一种技术性开放平台虽然目前来看跟B2C企业的开放平台关系不大但是也能从一定程度上说明开放平台是互联网企业的趋势。 第二种开放平台是指软件系统通过公开其应用程序编程接口API或函数function来使外部的程序可以增加该软件系统的功能或使用该软件系统的资源而不需要更改该软件系统的源代码。B2C企业开放平台又包含两种形式A淘宝商城、日本乐天这种纯平台的模式即自己不碰商品的进销存全部由入驻商家来做B美国亚马逊、当当网、京东商城这种“自营联营”的模式。 1.2 开放平台交互模型 三个角色 资源拥有者用户 客户端各种app、浏览器 服务提供方包含两个角色 认证服务器 资源服务器 1.2.1 认证服务器 认证服务器负责对用户进行认证并授权给客户端权限。一般的认证都是通过对账号密码进行验证实现而难点在于怎么进行授权。比如我们使用第三方登录 哔哩哔哩可以看到如使用 QQ 登录的授权页面上有 哔哩哔哩将获取以下权限 的字样以及权限信息 认证服务器需要知道请求授权的客户端的身份以及该客户端请求的权限。常见的做法是为每一个客户端预先分配一个 id并给每个 id 对应一个名称以及权限信息。这些信息可以写在认证服务器上的配置文件里今后客户端每次打开授权页面的时候客户端需要将该id发送到认证服务器0Auth2.0就可以用来自动给客户端分配id同时完成配置文件的自动更新。 1.3 OAuth2 开放平台 开放平台是由 OAuth2.0 协议发展而来的一个产品它的作用是让客户端自己去这上面进行注册、申请通过之后系统自动分配 客户端id 并完成配置的自动更新。 客户端要完成申请通常需要申请人填写客户端程序的类型Web、App、微信小程序、支付宝小程序等等、企业信息、营业执照、法人信息以及想要获取权限等信息申请需要得到得到服务提供上的审核通过之后开发平台才会自动分配一个客户端id给客户端。 在通过审核之后第三方应用在进行认证时就会想需要获取到的权限信息展示到页面上例如哔哩哔哩获取QQ权限。授权成功之后认证服务器需要把产生的 access_token 发送给客户端客户端才能访问具体的资源头像、性别之类的大致过程如下 让客户端在开放平台提交申请时候填写一个 网址例如www.baidu.com此网址主要用来获取认证码。 当有用户授权成功之后认证服务器将页面重定向到这个网址并将生成的 access_token拼接到该网址后面例如www.baidu.com?access_token123  客户端接收到access_token之后客户端就可以拿着这个token去获取需要的数据了 1.3.1 令牌 传统项目向服务端请求数据服务端需要频繁的去数据库查询用户名和密码并进行对比判断用户名和密码正确与否并作出相应提示这样效率非常低下怎么提高效率呢Token便应运而生。 Token是服务端生成的一串字符串以作客户端进行请求的一个令牌当第一次登录后服务器生成一个Token便将此Token返回给客户端以后客户端只需带上这个Token前来请求数据即可无需再次带上用户名和密码。减轻服务器的压力减少频繁的查询数据库使服务器更加健壮。 1.3.2 Access Token Access Token 是客户端访问资源服务器的令牌。拥有这个令牌代表着得到用户的授权即具备了访问资源的权限。同时这个授权应该是临时的只能在一定期限内使用。主要原因是因为Access Token 在使用的过程中很有可能会泄露被不法分子利用获取我们的数据。所以Access Token应该只能在某个期限内使用这样可以降低因 Access Token 泄露而带来的风险。 1.4 认证模式 OAuth2.0中定义了四种授权模式 authorization code 授权码模式 implicit 简化模式 resource owner password credentials 密码模式 client credentials 客户端模式 常见模式授权码、密码模式 1.4.1 授权码模式 授权码模式authorization code是功能最完整、流程最严密的授权模式code保证了token的安全性即使code被拦截由于没有secret也是无法通过code获得token的。 角色行为与功能 资源所有者 只需要允许或拒绝第三方应用获得授权 第三方应用 申请成为资源服务器的第三方应用 获取资源服务器提供的资源 授权服务器 提供授权许可code、令牌token等 资源服务器 提供给第三方应用开放资源的接口 时序图 环境搭建 创建父项目 指定打包方式为pom ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.woniuxy/groupIdartifactIdoauth2/artifactIdversion1.0-SNAPSHOT/versionpackagingpom/packaging /project 创建auth-server认证服务器模块 导入依赖 导入依赖版本如下 propertiesjava.version1.8/java.versionproject.build.sourceEncodingUTF-8/project.build.sourceEncodingproject.reporting.outputEncodingUTF-8/project.reporting.outputEncodingspring-boot.version2.3.7.RELEASE/spring-boot.versionspring-cloud-alibaba.version2.2.2.RELEASE/spring-cloud-alibaba.version /properties oauth2依赖 dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-oauth2/artifactIdversion2.2.4.RELEASE/version /dependency 创建用户信息配置类 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;Configuration EnableWebSecurity public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter{//密码编码器Beanpublic BCryptPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}// 基于内存的用户信息Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication() //内存认证.withUser(zhangsan) //用户名.password(passwordEncoder().encode(123)) //密码.authorities(ROLE_ADMIN); //角色} } 创建客户端配置类配置客户端信息 import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 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 javax.annotation.Resource;Configuration EnableAuthorizationServer public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter{Resourceprivate BCryptPasswordEncoder passwordEncoder;Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {//配置客户端clients.inMemory() //内存方式.withClient(client) //客户端名字.secret(passwordEncoder.encode(secret)) //客户端秘钥.authorizedGrantTypes(authorization_code)//授权类型.scopes(all) //授权范围.redirectUris(http://www.baidu.com); //回调网址携带授权码} } 在application.yml文件中配置以下信息 server:port: 8000 spring:application:name: oauth 启动项目进行登录 localhost:8000/login 进入登录页面输入账号zhangsan密码123进行登录 登录成功之后向服务器发送请求获取授权码在地址栏上输入以下内容回车 http://localhost:8080/oauth/authorize?client_idclientresponse_typecode 可以看到一个授权页面询问用户是否进行授权 授权成功之后会重定向到AuthorizationServerConfiguration配置类中指定的地址并以参数的方式携带授权码 通过postman发送请求向服务器获取token 地址栏填写http://client:secretlocalhost:8000/oauth/token 填写客户端账号密码 填写授权类型、授权码发送请求 成功之后在postman上可以看到以下信息 表示成功 注意每个授权码只能使用一次 1.4.2 密码模式 密码模式Resource Owner Password Credentials Grant中用户向客户端提供自己的用户名和密码。客户端使用这些信息向服务商提供商索要授权。 在这种模式中用户必须把自己的密码给客户端但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下比如客户端是操作系统的一部分或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下才能考虑使用这种模式。 修改AuthorizationServerConfiguration配置类添加密码模式 Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception {//配置客户端clients.inMemory() .withClient(client).secret(passwordEncoder.encode(secret)).authorizedGrantTypes(authorization_code,password) //添加密码授权模式.scopes(all) //授权范围.redirectUris(http://www.woniuxy.com); } 在postman中新开一个请求地址栏中填写http://localhost:8080/oauth/token 密码授权模式要求以请求头的方式提交客户端账号密码并且需要对账号密码进行base64加密因此选择Authorization选项卡设置TYPE为Basic Auth并填写客户端账号密码 在请求体中设置授权类型、用户账号密码参数 发送请求测试 可以发现此时并不支持密码模式即使在AuthorizationServerConfiguration配置类中指定了密码模式。 原因是此时代码中缺少对密码模式的支持在oauth2中需要添加AuthenticationManager对象对密码模式进行支持。 在WebSecurityConfiguration配置类中配置 AuthenticationManager // 配置 AuthenticationManager密码模式需要该对象进行账号密码校验 Bean Override public AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean(); } 在AuthorizationServerConfiguration类中注入AuthenticationManager并重写以下方法 // 认证管理器 Autowired private AuthenticationManager authenticationManager;//配置使用的 AuthenticationManager 实现用户认证的功能 Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager); } 重启项目再次发送请求获取token 整合JWT 导入了oauth2依赖就自动导入的JWT相关依赖因此不用单独导入JWT只需要进行设置就行 创建TokenConfiguration配置类 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; 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 public class TokenConfiguration {// 密码private static String SIGNING_KEYwww.woniuxy.com;// token转换器Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter jwtAccessTokenConverter new JwtAccessTokenConverter();jwtAccessTokenConverter.setSigningKey(SIGNING_KEY);return jwtAccessTokenConverter;}// 令牌存储策略:jwt方式Beanpublic TokenStore tokenStore(){return new JwtTokenStore(accessTokenConverter());} } 在AuthorizationServerConfiguration配置类中注入相关对象 Resource private TokenStore tokenStore;Resource private JwtAccessTokenConverter jwtAccessTokenConverter;Resource private ClientDetailsService clientDetailsService; 在AuthorizationServerConfiguration配置类中编写token服务方法该方法主要用来设置 private AuthorizationServerTokenServices tokenServices(){// 创建服务对象DefaultTokenServices services new DefaultTokenServices();// 设置客户端详情服务services.setClientDetailsService(clientDetailsService);// 支持刷新令牌services.setSupportRefreshToken(true);// 不重复使用refreshtoken每次刷新之后只能用新的refreshtoken才能继续刷新services.setReuseRefreshToken(false);// 设置令牌存储策略services.setTokenStore(tokenStore);// 设置令牌增强TokenEnhancerChain tokenEnhancerChain new TokenEnhancerChain();tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));services.setTokenEnhancer(tokenEnhancerChain);// 设置令牌过期时间services.setAccessTokenValiditySeconds(600);services.setRefreshTokenValiditySeconds(6000);return services; } 修改configure(AuthorizationServerEndpointsConfigurer endpoints)方法添加token服务 //配置使用的 AuthenticationManager 实现用户认证的功能 Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.authenticationManager(authenticationManager) // 认证管理器.tokenServices(tokenServices()); // 配置token服务 } 重启项目发送请求获取token 如果想要获取到refreshtoken可以修改AuthorizationServerConfiguration配置类添加refresh_token授权方式 Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception {//配置客户端clients.inMemory() .withClient(client).secret(passwordEncoder.encode(secret)) .authorizedGrantTypes(authorization_code,password,refresh_token) .scopes(all).redirectUris(http://www.woniuxy.com); } 重启项目测试 整合数据库(user) 建表SQL create database sc default character setutf8;DROP TABLE IF EXISTS perms; CREATE TABLE perms (id int(11) DEFAULT NULL,name varchar(20) DEFAULT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8;INSERT INTO perms VALUES (3001,user:add),(3002,user:del),(3003,user:find),(3004,user:update),(3005,goods:add),(3006,goods:find),(3007,goods:del),(3008,goods:update);DROP TABLE IF EXISTS role; CREATE TABLE role (id int(11) DEFAULT NULL,name varchar(20) DEFAULT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8;INSERT INTO role VALUES (2001,ROLE_ADMIN),(2002,ROLE_USER);DROP TABLE IF EXISTS role_perms; CREATE TABLE role_perms (rid int(11) DEFAULT NULL,pid int(11) DEFAULT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8;INSERT INTO role_perms VALUES (2001,3001),(2001,3003),(2001,3004),(2002,3005),(2002,3006),(2002,3007),(2002,3008);DROP TABLE IF EXISTS user; CREATE TABLE user (id int(11) DEFAULT NULL,username varchar(20) DEFAULT NULL,password varchar(64) DEFAULT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8;INSERT INTO user VALUES (1001,zhangsan,$2a$10$pINVnd8.cXScFXCxI2x4cem4fOexA2J5TNY/Mx2CjN6mJuYGBNG0m),(1002,wangwu,wangwu);DROP TABLE IF EXISTS user_role; CREATE TABLE user_role (uid int(11) DEFAULT NULL,rid int(11) DEFAULT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8;INSERT INTO user_role VALUES (1001,2001),(1002,2002),(1003,2002); auth-server的pom.xml中引入mybatis !--mybatis-- dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion2.1.4/version /dependency 在application.yml中配置mybatis参数 mybatis:type-aliases-package: com.woniuxy.authserver.entitymapper-locations: classpath:/mapper/*.xml 创建Perms、Role、User实体类注意实体类必须实现序列化接口不然运行过程中可能会报Failed to find access token for token错误 import lombok.Data;Data public class Perms implements Serializable {private static final long serialVersionUID 1L;private int id;private String name; } import lombok.Data; import java.util.List;Data public class Role implements Serializable {private static final long serialVersionUID 1L;private int id;private String name;private ListPerms perms; } import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails;import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.List;Slf4j Data NoArgsConstructor AllArgsConstructor public class User implements UserDetails, Serializable {private static final long serialVersionUID 1L;private int id;private String username;private String password;private ListRole roles;// 返回当前用户的所有角色、权限信息Overridepublic Collection? extends GrantedAuthority getAuthorities() {log.debug(获取用户角色权限信息);// 新建集合ListGrantedAuthority grantedAuthorities new ArrayList();// 遍历rolefor(Role role : this.roles){// 放入角色信息grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));// 遍历当前角色的所有权限信息for(Perms perms : role.getPerms()){grantedAuthorities.add(new SimpleGrantedAuthority(perms.getName()));}}log.debug(grantedAuthorities.toString());return grantedAuthorities;}// 获取用户名Overridepublic String getUsername() {return this.username;}// 账号是否过期 true表示未过期 false表示过期Overridepublic boolean isAccountNonExpired() {return true;}// 账号是否被锁定 true表示未锁定 false表示锁定Overridepublic boolean isAccountNonLocked() {return true;}// 凭证是否过期 true表示未过期 false表示过期Overridepublic boolean isCredentialsNonExpired() {return true;}// 用户是否被禁用 true表示未禁用 false表示禁用Overridepublic boolean isEnabled() {return true;} } 创建UerMapper接口 import com.woniuxy.springsecurity.entity.User; import org.apache.ibatis.annotations.Mapper;Mapper public interface UserMapper {public User findByName(String username); } 在resources目录下创建mapper文件夹并在该文件夹下创建Mapper文件 ?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.woniuxy.authserver.mapper.UserMapper select idfindByName resultMapuser_mapselect * from user where username #{username}/selectresultMap iduser_map typeUserid columnid propertyid/idresult columnusername propertyusername/resultresult columnpassword propertypassword/resultcollection propertyroles ofTypeRole columnid selectfindRolesByUid/collection/resultMapselect idfindRolesByUid resultMaprole_mapselect r.id,r.name from user_role ur,role r where ur.rid r.id and ur.uid #{id}/selectresultMap idrole_map typeRoleid columnid propertyid/idresult columnname propertyname/resultcollection propertyperms ofTypePerms columnid selectfindPermsByRid/collection/resultMapselect idfindPermsByRid resultTypePermsselect p.id,p.name from role_perms rp,perms p where rp.pid p.id and rp.rid #{rid}/select /mapper 创建CustomUserDetailsServiceImpl类实现UserDetailsService接口 import com.woniuxy.authserver.entity.User; import com.woniuxy.authserver.mapper.UserMapper; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service;import javax.annotation.Resource;Service public class CustomUserDetailsServiceImpl implements UserDetailsService {Resourceprivate UserMapper userMapper;Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//1.查询用户User user userMapper.findByName(username);//2.判断if (user null) throw new UsernameNotFoundException(用户不存在);//3.返回用户信息return user;} } 在配置类WebSecurityConfiguration中注入UserDetailsService对象并修改configure(AuthenticationManagerBuilder auth)反方指定用户信息从数据库中获取 Resource private UserDetailsService userDetailsService;Override protected void configure(AuthenticationManagerBuilder auth) throws Exception {//auth//.inMemoryAuthentication() //内存认证//.withUser(zhangsan) //用户名//.password(passwordEncoder().encode(123)) //密码//.authorities(ROLE_ADMIN); //角色auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } 重启auth-server服务进行认证 封装用户id 在生成token时可以将用户id封装到token中以便后期使用 修改TokenConfiguration类中的accessTokenConverter()方法在创建转换器时重写enhance方法 // token转换器 Bean public JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter jwtAccessTokenConverter new JwtAccessTokenConverter(){Overridepublic OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {final MapString,Object map new HashMap();// 从认证对象中得到用户信息User user (User) authentication.getUserAuthentication().getPrincipal();// 将用户id放到token中map.put(uid, user.getId());((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(map);// 返回return super.enhance(accessToken, authentication);}};jwtAccessTokenConverter.setSigningKey(SIGNING_KEY);return jwtAccessTokenConverter; } 利用postman进行测试 返回的结果中可以看到用户idtoken中也包含了用户id 检验token是否过期 在org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint类中定义了校验token的接口/oauth/check_token该接口可以用来校验token是否合法、是否过期、是否是伪造的 RequestMapping(value /oauth/check_token) ResponseBody public MapString, ? checkToken(RequestParam(token) String value) {OAuth2AccessToken token resourceServerTokenServices.readAccessToken(value);if (token null) {throw new InvalidTokenException(Token was not recognised);}if (token.isExpired()) {throw new InvalidTokenException(Token has expired);}OAuth2Authentication authentication resourceServerTokenServices.loadAuthentication(token.getValue());MapString, Object response (MapString, Object)accessTokenConverter.convertAccessToken(token, authentication);// gh-1070response.put(active, true); // Always true if token exists and not expiredreturn response; } 只是该接口oauth2默认情况下是不对外公开的如果要使用该接口那就必须手动配置开启在AuthorizationServerConfiguration配置类中重写以下方法 //设置 /oauth/check_token 端点通过认证后可访问。 //该端点对应 CheckTokenEndpoint类用于校验访问令牌的有效性。 //在客户端访问资源服务器时会在请求中带上访问令牌。 //在资源服务器收到客户端的请求时会使用请求中的访问令牌找授权服务器确认该访问令牌的有效性。 Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {// 默认是denyAll()拒绝所有oauthServer.checkTokenAccess(permitAll()); } checkTokenAccess常用值有三种 denyAll()拒绝所有请求不开放该接口 isAuthenticated()只对完成认证之后的请求开放 permitAll()对所有请求开放 测试登录成功之后在Postman中发送请求进行测试 接口urlhttp://localhost:8080/oauth/check_token 返回的结果中包含了用户的用户名、权限等信息还包括了token是否可用的信息 如果返回以下信息表示token已经过期 而如果返回以下信息表示token非法 通过refresh_token获取新token 获取token和刷新token使用的是同一个接口所以地址栏url还是 http://local:8080/oauth/token 只是grant_type需要换成refresh_token然后将之前的refresh token作为参数传递给后台 还是需要将客户端id、密码以base64编码放到请求头中 发送请求得到结果 根据结果可以知道token和refresh_token都会自动刷新这样做的好处是当token过期时通过程序调用刷新接口获取到新的token和refresh_token实现自动续期。 refresh_token如果过期会得到以下结果 refresh_token过期就需要重新登录 1.5 资源服务器 创建resource子模块导入相关依赖 设置父子关系 创建OAuth2ResourceServerConfig配置类 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;Configuration EnableResourceServer public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests()// 设置请求需要认证后访问.anyRequest().authenticated();} } 创建controller import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;RestController RequestMapping(/resource) public class ResourceController {RequestMapping(/info)public String info(){return success;} } 配置application.yml server:port: 8001 spring:application:name: resource security:oauth2:# OAuth2 Client 配置对应 OAuth2ClientProperties 类client:client-id: clientclient-secret: secret# OAuth2 Resource 配置对应 ResourceServerProperties 类resource:token-info-uri: http://127.0.0.1:8000/oauth/check_token # 获得 Token 信息的 URL# 访问令牌获取 URL自定义的access-token-uri: http://127.0.0.1:8000/oauth/token management:endpoints:web:exposure:include: * 启动resource资源服务器 先进行认证得到token和refresh_token localhost:8000/oauth/token 然后将得到的token放到请求资源服务器的请求头中 发送请求后可以发现报500错误查看resource控制台可以发现以下信息 org.springframework.web.client.HttpClientErrorException$Forbidden: 403 : [{timestamp:2022-05-07T03:40:14.06300:00,status:403,error:Forbidden,message:,path:/oauth/check_token}] 根据信息提示没有权限访问 /oauth/check_token该URL是认证服务器用来校验token是否合法的接口。资源服务器在接收到请求时会获取到token然后调用认证服务器的/oauth/check_token接口去检验token但是此时认证服务器还没有开放该端口默认关闭所以造成了403无法访问。 到认证服务器的AuthorizationServerConfiguration配置类中开启/oauth/check_token //设置 /oauth/check_token 端点通过认证后可访问。 //该端点对应 CheckTokenEndpoint类用于校验访问令牌的有效性。 //在客户端访问资源服务器时会在请求中带上访问令牌。 //在资源服务器收到客户端的请求时会使用请求中的访问令牌找授权服务器确认该访问令牌的有效性。 Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {// 默认是denyAll()拒绝所有oauthServer.checkTokenAccess(isAuthenticated()); } 重启认证服务器 重新进行认证得到token然后用新的token再访问资源服务器 看到success表明成功 角色权限管理 在资源服务器主启动类上添加EnableGlobalMethodSecurity注解开启spring security权限注解的支持 import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;SpringBootApplication EnableGlobalMethodSecurity(prePostEnabled true) public class ResourceApplication {public static void main(String[] args) {SpringApplication.run(ResourceApplication.class, args);} } 在resource/info接口方法上添加注解PreAuthorize并指定角色或权限 RequestMapping(/info) PreAuthorize(hasRole(USER)) public String info(){return success; } 利用postman再次访问该接口 得到不允许访问的结果表明角色权限管理生效 1.6 整合数据库(client) 建表SQL CREATE TABLE clientdetails (appId VARCHAR(128) NOT NULL,resourceIds VARCHAR(256) DEFAULT NULL,appSecret VARCHAR(256) DEFAULT NULL,scope VARCHAR(256) DEFAULT NULL,grantTypes VARCHAR(256) DEFAULT NULL,redirectUrl VARCHAR(256) DEFAULT NULL,authorities VARCHAR(256) DEFAULT NULL,access_token_validity INT(11) DEFAULT NULL,refresh_token_validity INT(11) DEFAULT NULL,additionalInformation VARCHAR(4096) DEFAULT NULL,autoApproveScopes VARCHAR(256) DEFAULT NULL,PRIMARY KEY (appId) ) ENGINEINNODB DEFAULT CHARSETutf8;CREATE TABLE oauth_access_token (token_id VARCHAR(256) DEFAULT NULL,token BLOB,authentication_id VARCHAR(128) NOT NULL,user_name VARCHAR(256) DEFAULT NULL,client_id VARCHAR(256) DEFAULT NULL,authentication BLOB,refresh_token VARCHAR(256) DEFAULT NULL,PRIMARY KEY (authentication_id) ) ENGINEINNODB DEFAULT CHARSETutf8;CREATE TABLE oauth_approvals (userId VARCHAR(256) DEFAULT NULL,clientId VARCHAR(256) DEFAULT NULL,scope VARCHAR(256) DEFAULT NULL,status VARCHAR(10) DEFAULT NULL,expiresAt TIMESTAMP NULL DEFAULT NULL,lastModifiedAt TIMESTAMP NULL DEFAULT NULL ) ENGINEINNODB DEFAULT CHARSETutf8;CREATE TABLE oauth_client_details (client_id VARCHAR(128) NOT NULL,resource_ids VARCHAR(256) DEFAULT NULL,client_secret VARCHAR(256) DEFAULT NULL,scope VARCHAR(256) DEFAULT NULL,authorized_grant_types VARCHAR(256) DEFAULT NULL,web_server_redirect_uri VARCHAR(256) DEFAULT NULL,authorities VARCHAR(256) DEFAULT NULL,access_token_validity INT(11) DEFAULT NULL,refresh_token_validity INT(11) DEFAULT NULL,additional_information VARCHAR(4096) DEFAULT NULL,autoapprove VARCHAR(256) DEFAULT NULL,PRIMARY KEY (client_id) ) ENGINEINNODB DEFAULT CHARSETutf8;CREATE TABLE oauth_client_token (token_id VARCHAR(256) DEFAULT NULL,token BLOB,authentication_id VARCHAR(128) NOT NULL,user_name VARCHAR(256) DEFAULT NULL,client_id VARCHAR(256) DEFAULT NULL,PRIMARY KEY (authentication_id) ) ENGINEINNODB DEFAULT CHARSETutf8;CREATE TABLE oauth_code (code VARCHAR(256) DEFAULT NULL,authentication BLOB ) ENGINEINNODB DEFAULT CHARSETutf8;CREATE TABLE oauth_refresh_token (token_id VARCHAR(256) DEFAULT NULL,token BLOB,authentication BLOB ) ENGINEINNODB DEFAULT CHARSETutf8; 在表 oauth_client_details 中增加一条客户端配置记录在填入时可以按照AuthorizationServerConfiguration配置类中的客户端配置进行配置 配置的效果如下 注各字段解释说明 client_id客户端标识 client_secret客户端安全码。注意安全码不能是明文需要加密此处可以写一段程序然后使用BCryptPasswordEncoder为客户端安全码加密得到加密之后的安全码再写入到数据库中例如 System.out.println(new BCryptPasswordEncoder().encode(secret)); scope客户端授权范围 authorized_grant_types客户端授权类型支持多种类型多种类型之间用逗号隔开 web_server_redirect_uri服务器回调地址 创建实体类User、Role、Perms 在auth-server模块的pom.xml中引入mybatis相关依赖 !-- spring-boot-starter-jdbc 内置了HikariCP 连接池所以使用该连接池连接数据库 -- dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jdbc/artifactId /dependency !-- mysql -- dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId /dependency !-- 获取application.yml文件中的配置 -- dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-configuration-processor/artifactIdoptionaltrue/optional /dependency application.yml文件中添加数据库相关配置 server:port: 8000 spring:application:name: oauthdatasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/sc?useUnicodetruecharacterEncodingutf8serverTimezoneUTCusername: rootpassword: roothikari:minimum-idle: 5maximum-pool-size: 10auto-commit: true #自动提交pool-name: MYHIKARICPconnection-test-query: SELECT 1 #测试是否能连接上数据库的SQL语句main:#true后定义的bean会覆盖之前定义的相同名称的bean生成dataSource替换掉原生的dataSourceallow-bean-definition-overriding: true 创建数据库配置类DataSourceConfiguration主要配置用到的数据源用HikariCP连接池的数据源替换到spring内置的数据源。 import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary;import javax.sql.DataSource;Configuration public class DataSourceConfiguration {Bean Primary //根据application.yml中的配置信息创建dataSourceConfigurationProperties(prefix spring.datasource)//import javax.sql.DataSource;public DataSource dataSource() {//创建dataSourcereturn DataSourceBuilder.create().build();} } 在TokenConfiguration配置类中把token存储策略改成JDBC方式将jwt存放到数据库中DataSource Resource private DataSource dataSource;// 令牌存储策略:jwt方式 Bean public TokenStore tokenStore(DataSource dataSource){//return new JwtTokenStore(accessTokenConverter());return new JdbcTokenStore(dataSource); } 修改AuthorizationServerConfiguration配置类添加ClientDetailsService clientDetailsService(DataSource dataSource)方法让程序通过DataSource从数据库中获取到客户端信息 Bean public ClientDetailsService clientDetailsService(DataSource dataSource) {//在数据库中去获取客户端信息oauth_client_details表return new JdbcClientDetailsService(dataSource); } 修改configure(ClientDetailsServiceConfigurer clients)方法指定到数据库获取客户端信息 Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception {//配置客户端//clients//.inMemory() //内存方式//.withClient(client) //客户端名字//.secret(passwordEncoder.encode(secret)) //客户端秘钥//.authorizedGrantTypes(authorization_code,password,refresh_token)//.scopes(all) //授权范围//.redirectUris(http://www.woniuxy.com); //回调网址clients.withClientDetails(clientDetailsService); } 完成之后重启项目再次进行认证测试 正常情况下测试完毕之后会在数据库的oauth_access_token 表中会增加一个记录这个记录就是浏览器获取到的token和refresh token 角色、权限管理测试 在resource服务的controller中添加以下方法 RequestMapping(/message) PreAuthorize(hasRole(ADMIN)) public String message(){return message; }RequestMapping(/data) PreAuthorize(hasAuthority(user:add)) public String data(){return data; } RequestMapping(/test) PreAuthorize(hasAuthority(user:del)) public String test(){return test; } 启动resource服务通过postman分别测试info、message、data、test接口如果只有message、data接口可以访问那么说明角色、权限管理成功。
http://www.zqtcl.cn/news/279584/

相关文章:

  • 大淘客怎么自己做网站自己开网站能赚钱吗
  • 大型门户网站开发北京网站建设管庄
  • 大连建设工程网站网站建设组织管理怎么写
  • wordpress英文站注册域名需要注意什么
  • 营销型网站的建设重点是什么深圳logo设计公司排名
  • 做网站的用什么软件呢网站排名优化服务公司
  • 网站开发完整视频网站集约化建设较好的城市
  • 网站建设和平面设计应用网站如何做
  • 自己做网站需要多少费用asa8.4 做网站映射
  • 商业网站 模板黑龙江省建设厅安全员考试
  • 网站新备案不能访问室内装修网站模板
  • 工程师报考网站wordpress设置视频图片不显示图片
  • 徐州网站建设公司排名成都住建平台
  • 用来备案企业网站国外免费外贸网站
  • 网页背景做的比较好的网站做一个企业网站价格
  • 免费制图网站县级门户网站建设的报告
  • 北京网站建设网怎么用手机做一个网站
  • 网站建设管理办法关于公司门户网站建设的议案
  • 网站开发入职转正申请书体验好的网站
  • 在线精品课程网站开发网站备案号怎么修改
  • 网站建设 风险百度热搜的含义
  • 怎样创作网站公司做网站 要准备哪些素材
  • 网站上的平面海报怎么做南阳企业做网站
  • 佛山公众平台网站推广多少钱wordpress如何调用分类目录
  • 网站推广应该注意什么信息发布平台推广
  • 官方网站案例做网站私活在哪接
  • 做网站滨州wordpress 不同域名
  • 找人做设计的网站广州做网站(信科网络)
  • 如何选择网站做站方向青之峰网站建设
  • 福州哪家网站制作设计高端还实惠设计logo的理念