diff --git a/pom.xml b/pom.xml index 6d95c7a..86ae5c3 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,8 @@ 4.4 2.11.0 1.1.0 + 5.8.8 + 3.5.0 3.0.3 @@ -250,6 +252,16 @@ sharding-jdbc-spring-boot-starter ${shardingsphere.version} + + cn.hutool + hutool-all + ${hutool.version} + + + com.google.zxing + core + ${zxing.version} + diff --git a/server/zyjblogs-oauth/pom.xml b/server/zyjblogs-oauth/pom.xml index f699a8c..f9af723 100644 --- a/server/zyjblogs-oauth/pom.xml +++ b/server/zyjblogs-oauth/pom.xml @@ -77,6 +77,15 @@ org.springframework.boot spring-boot-devtools + + cn.hutool + hutool-all + + + com.google.zxing + core + 3.3.3 + diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/AuthorizationServerConfiguration.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/AuthorizationServerConfiguration.java index 2a1a7f5..9641609 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/AuthorizationServerConfiguration.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/AuthorizationServerConfiguration.java @@ -1,20 +1,30 @@ package cn.zyjblogs.config.security; import cn.zyjblogs.config.security.policy.OauthAuthorizationCodeServices; +import cn.zyjblogs.config.security.policy.QrCodeTokenGranter; import cn.zyjblogs.starter.redis.utils.RedisTemplateHandler; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; +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.ClientDetailsService; +import org.springframework.security.oauth2.provider.CompositeTokenGranter; +import org.springframework.security.oauth2.provider.TokenGranter; +import org.springframework.security.oauth2.provider.TokenRequest; +import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenGranter; import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; +import org.springframework.security.oauth2.provider.code.AuthorizationCodeTokenGranter; +import org.springframework.security.oauth2.provider.implicit.ImplicitTokenGranter; +import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter; +import org.springframework.security.oauth2.provider.refresh.RefreshTokenGranter; import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; import org.springframework.security.oauth2.provider.token.DefaultTokenServices; import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; @@ -22,6 +32,7 @@ import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import javax.sql.DataSource; +import java.util.ArrayList; import java.util.List; /** @@ -81,13 +92,13 @@ public class AuthorizationServerConfiguration extends AuthorizationServerConfigu */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { - endpoints //密码模式 - .authenticationManager(authenticationManager) +// .authenticationManager(authenticationManager) //授权码模式 - .authorizationCodeServices(authorizationCodeServices(dataSource)) - .tokenServices(tokenServices()) +// .authorizationCodeServices(authorizationCodeServices()) +// .tokenServices(tokenServices()) + .tokenGranter(tokenGranter(endpoints)) .accessTokenConverter(accessTokenConverter) //允许表单认证 .allowedTokenEndpointRequestMethods(HttpMethod.POST) @@ -95,6 +106,39 @@ public class AuthorizationServerConfiguration extends AuthorizationServerConfigu .exceptionTranslator(oAuthResponseExceptionTranslator); } + private TokenGranter tokenGranter(AuthorizationServerEndpointsConfigurer endpoints) { + return new TokenGranter() { + private CompositeTokenGranter delegate; + + @Override + public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) { + if (delegate == null) { + delegate = getTokenGranters(endpoints); + } + return delegate.grant(grantType, tokenRequest); + } + }; + + } + + /** + * m + * 授权模式 + * + * @param endpoints + * @return + */ + private CompositeTokenGranter getTokenGranters(AuthorizationServerEndpointsConfigurer endpoints) { + List list = new ArrayList<>(); + list.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices(), clientDetails(dataSource), endpoints.getOAuth2RequestFactory())); + list.add(new RefreshTokenGranter(tokenServices(), clientDetails(dataSource), endpoints.getOAuth2RequestFactory())); + list.add(new AuthorizationCodeTokenGranter(tokenServices(), authorizationCodeServices(), clientDetails(dataSource), endpoints.getOAuth2RequestFactory())); + list.add(new ImplicitTokenGranter(tokenServices(), clientDetails(dataSource), endpoints.getOAuth2RequestFactory())); + list.add(new ClientCredentialsTokenGranter(tokenServices(), clientDetails(dataSource), endpoints.getOAuth2RequestFactory())); + list.add(new QrCodeTokenGranter(tokenServices(), clientDetails(dataSource), endpoints.getOAuth2RequestFactory())); + return new CompositeTokenGranter(list); + } + /** * 令牌管理服务 * @@ -128,7 +172,7 @@ public class AuthorizationServerConfiguration extends AuthorizationServerConfigu } @Bean - public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) { + public AuthorizationCodeServices authorizationCodeServices() { //设置授权码模式的授权码如何存取 return new OauthAuthorizationCodeServices(redisTemplateHandler); // return new JdbcAuthorizationCodeServices(dataSource); diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/ResourceServerConfig.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/ResourceServerConfig.java index c7d4985..152a234 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/ResourceServerConfig.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/ResourceServerConfig.java @@ -13,6 +13,8 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.R import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.TokenStore; +import java.util.List; + /** * @author zhuyijun */ @@ -48,18 +50,19 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter { */ @Override public void configure(HttpSecurity http) throws Exception { + List allowPaths = whiteListProperties.getAllowPaths(); + String[] strings = allowPaths.toArray(new String[0]); http.csrf().disable() // .disable() //限制资源服务器作用范围为 "/user/**", "/demo/**" - .requestMatchers().antMatchers("/v*/**", "/demo/**", - String.join(",", whiteListProperties.getAllowPaths())) + .requestMatchers().antMatchers("/v*/**", "/demo/**").antMatchers(strings) .and() .formLogin() .and() .authorizeRequests() - .antMatchers(String.join(",", whiteListProperties.getAllowPaths())) + .antMatchers(strings).permitAll() + .antMatchers("/v*/user/login", "/v*/auth/refresh/token", "/v*/auth/authorize/code") .permitAll() - .antMatchers("/v*/user/login", "/v*/auth/refresh/token", "/v*/auth/authorize/code").permitAll() .antMatchers("/v*/**").access("#oauth2.hasAnyScope('oauth','all')") //以下请求必须认证通过 .anyRequest() diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/WebSecurityConfiguration.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/WebSecurityConfiguration.java index 5809679..879c90b 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/WebSecurityConfiguration.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/WebSecurityConfiguration.java @@ -53,7 +53,11 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); //使HttpSecurity接收以"/login/","/oauth/"开头请求, 配置HttpSecurity不阻止swagger页面 - http.authorizeRequests() + http +// .requestMatchers().antMatchers("/login") +// .and() + .authorizeRequests() + // .antMatchers("/webjars/**", "/swagger-ui.html/**", "/swagger-resources/**", "/v2/api-docs/**") // .permitAll() // .antMatchers("/user/logout", "/login", "/oauth/**", "/user/login", "/user/refresh/token").permitAll() diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/policy/QrCodeTokenGranter.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/policy/QrCodeTokenGranter.java new file mode 100644 index 0000000..5ea380b --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/config/security/policy/QrCodeTokenGranter.java @@ -0,0 +1,26 @@ +package cn.zyjblogs.config.security.policy; + +import cn.zyjblogs.server.user.dto.AuthorizationDto; +import org.springframework.security.oauth2.provider.*; +import org.springframework.security.oauth2.provider.token.AbstractTokenGranter; +import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; + +public class QrCodeTokenGranter extends AbstractTokenGranter { + private static final String GRANT_TYPE = "qrcode"; + + protected QrCodeTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory, String grantType) { + super(tokenServices, clientDetailsService, requestFactory, grantType); + } + + public QrCodeTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService + , OAuth2RequestFactory requestFactory) { + this(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE); + } + + @Override + protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) { + AuthorizationDto authorization = new AuthorizationDto().createAuthorization(); + OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest); + return new OAuth2Authentication(storedOAuth2Request, authorization); + } +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/constant/QrCodeEnum.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/constant/QrCodeEnum.java new file mode 100644 index 0000000..ed0205b --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/constant/QrCodeEnum.java @@ -0,0 +1,23 @@ +package cn.zyjblogs.server.qrcode.constant; + +public enum QrCodeEnum { + EXPIRE(0, "过期"), + NO_EXPIRE(1, "过期"), + NO_EXPIRE_HAS_TOKEN(2, "过期"); + + QrCodeEnum(int code, String name) { + this.code = code; + this.name = name; + } + + private int code; + private String name; + + public int getCode() { + return code; + } + + public String getName() { + return name; + } +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/controller/QrCodeController.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/controller/QrCodeController.java new file mode 100644 index 0000000..859d03b --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/controller/QrCodeController.java @@ -0,0 +1,89 @@ +package cn.zyjblogs.server.qrcode.controller; + +import cn.hutool.extra.qrcode.QrCodeUtil; +import cn.zyjblogs.server.qrcode.dto.QrCode; +import cn.zyjblogs.server.qrcode.service.QrCodeSerive; +import cn.zyjblogs.server.user.handler.OauthRquestHander; +import cn.zyjblogs.server.user.vo.OAuth2AccessTokenVo; +import cn.zyjblogs.starter.common.entity.response.HttpCode; +import cn.zyjblogs.starter.common.entity.response.ResponseObject; +import cn.zyjblogs.starter.common.entity.response.ResponseResult; +import cn.zyjblogs.starter.common.exception.AuthRuntimeException; +import cn.zyjblogs.starter.web.apiversion.ApiVersion; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.LinkedHashMap; +import java.util.Map; + +@ApiVersion(1) +@RequestMapping("/{v}/qrcode") +@RestController +@ResponseBody +@RequiredArgsConstructor +public class QrCodeController { + private final QrCodeSerive qrCodeSerive; + @Value("${zyjblogs.qrcode.redirect_url}") + private String qrcodeRedirectUrl; + + //获取登录二维码、放入Token + @GetMapping("/get") + @ApiVersion(1) + public void createCodeImg(HttpServletRequest request, HttpServletResponse response, @RequestParam("appid") String appid) { + response.setHeader("Pragma", "No-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.setContentType("image/jpeg"); + + try { + QrCode qrCode = qrCodeSerive.createQrId(appid); + Cookie cookie = new Cookie("qrsig", qrCode.getQrsig()); + response.addCookie(cookie); + Map query = new LinkedHashMap<>(); + query.put("k", qrCode.getQrsig()); + query.put("f", qrCode.getClienId()); + //这里没啥操作 就是生成一个UUID插入 数据库的表里 + QrCodeUtil.generate(OauthRquestHander.append(qrcodeRedirectUrl, query, false), 111, 111, "png", response.getOutputStream()); + + } catch (Exception e) { + throw new AuthRuntimeException(HttpCode.BAD_REQUEST, e.getMessage()); + } + } + + /** + * 判断是否过期 + * + * @param k + * @param f + * @return + */ + @GetMapping("/isQrExpire") + @ApiVersion(1) + public Integer isQrExpire(@RequestParam("k") String k, @RequestParam("f") String f) { + try { + return qrCodeSerive.isQrExpire(k, f); + } catch (Exception e) { + throw new AuthRuntimeException(HttpCode.BAD_REQUEST, e.getMessage()); + } + } + + /** + * 获取登录token + * + * @param k + * @param f + * @return + */ + @GetMapping("/login") + @ApiVersion(1) + public ResponseObject getToken(@RequestParam("k") String k, @RequestParam("f") String f) { + try { + return ResponseResult.success(qrCodeSerive.getToken(k, f)); + } catch (Exception e) { + throw new AuthRuntimeException(HttpCode.BAD_REQUEST, e.getMessage()); + } + } +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/dto/QrCode.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/dto/QrCode.java new file mode 100644 index 0000000..88ffbb9 --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/dto/QrCode.java @@ -0,0 +1,19 @@ +package cn.zyjblogs.server.qrcode.dto; + +import cn.zyjblogs.server.user.vo.OAuth2AccessTokenVo; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class QrCode implements Serializable { + private String qrsig; + private String clienId; + private OAuth2AccessTokenVo token; +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/service/QrCodeSerive.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/service/QrCodeSerive.java new file mode 100644 index 0000000..a066ecd --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/service/QrCodeSerive.java @@ -0,0 +1,24 @@ +package cn.zyjblogs.server.qrcode.service; + +import cn.zyjblogs.server.qrcode.dto.QrCode; +import cn.zyjblogs.server.user.vo.OAuth2AccessTokenVo; + +public interface QrCodeSerive { + /** + * 获取验证码id + * + * @return + */ + QrCode createQrId(String clientId); + + /** + * 校验验证码是否过期 + * + * @return + */ + Integer isQrExpire(String qrsig, String clientId); + + OAuth2AccessTokenVo getToken(String qrsig, String clientId); + + +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/service/impl/QrCodeSeriveImpl.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/service/impl/QrCodeSeriveImpl.java new file mode 100644 index 0000000..4f40abf --- /dev/null +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/qrcode/service/impl/QrCodeSeriveImpl.java @@ -0,0 +1,66 @@ +package cn.zyjblogs.server.qrcode.service.impl; + +import cn.hutool.core.util.IdUtil; +import cn.zyjblogs.server.qrcode.constant.QrCodeEnum; +import cn.zyjblogs.server.qrcode.dto.QrCode; +import cn.zyjblogs.server.qrcode.service.QrCodeSerive; +import cn.zyjblogs.server.user.vo.OAuth2AccessTokenVo; +import cn.zyjblogs.starter.common.entity.constant.CommonRedisKeyConstant; +import cn.zyjblogs.starter.common.entity.response.HttpCode; +import cn.zyjblogs.starter.common.exception.AuthRuntimeException; +import cn.zyjblogs.starter.redis.utils.RedisTemplateHandler; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.concurrent.TimeUnit; + +@Service +@RequiredArgsConstructor +public class QrCodeSeriveImpl implements QrCodeSerive { + private final RedisTemplateHandler redisTemplateHandler; + + @Override + public QrCode createQrId(String clientId) { + if (clientId == null) { + throw new AuthRuntimeException(HttpCode.BAD_REQUEST, "appid不能为空"); + } + String id2 = IdUtil.objectId(); + QrCode qrCode = QrCode.builder() + .clienId(clientId) + .qrsig(id2) + .build(); + redisTemplateHandler.set(getRediKey(qrCode.getQrsig(), qrCode.getClienId()), null, 3, TimeUnit.MINUTES); + return qrCode; + } + + public String getRediKey(String qrsig, String clientId) { + return CommonRedisKeyConstant.QR_CODE + ":" + clientId + ":" + qrsig; + } + + @Override + public Integer isQrExpire(String qrsig, String clientId) { + String rediKey = getRediKey(qrsig, clientId); + Boolean aBoolean = redisTemplateHandler.hasKey(rediKey); + if (!aBoolean) { + return QrCodeEnum.EXPIRE.getCode(); + } + QrCode qrCode = redisTemplateHandler.get(rediKey); + if (qrCode == null) { + return QrCodeEnum.EXPIRE.getCode(); + } + if (qrCode.getToken() == null) { + return QrCodeEnum.NO_EXPIRE.getCode(); + } + return QrCodeEnum.NO_EXPIRE_HAS_TOKEN.getCode(); + } + + @Override + public OAuth2AccessTokenVo getToken(String qrsig, String clientId) { + QrCode qrCode = redisTemplateHandler.get(getRediKey(qrsig, clientId)); + if (qrCode != null && qrCode.getToken() != null) { + return qrCode.getToken(); + } + return null; + } + +} diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/controller/AuthController.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/controller/AuthController.java index a9256f5..779d168 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/controller/AuthController.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/controller/AuthController.java @@ -5,17 +5,16 @@ import cn.zyjblogs.server.user.dto.AuthorizationCodeDto; import cn.zyjblogs.server.user.dto.OAuth2AccessTokenDto; import cn.zyjblogs.server.user.service.AuthService; import cn.zyjblogs.server.user.vo.OAuth2AccessTokenVo; +import cn.zyjblogs.starter.common.entity.response.HttpCode; import cn.zyjblogs.starter.common.entity.response.ResponseObject; import cn.zyjblogs.starter.common.entity.response.ResponseResult; +import cn.zyjblogs.starter.common.exception.AuthRuntimeException; import cn.zyjblogs.starter.web.apiversion.ApiVersion; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; /** * @author zhuyijun @@ -55,4 +54,14 @@ public class AuthController { public ResponseObject getTokenByAuthorizationCode(@RequestBody @Validated AuthCodeDto authCodeDto) { return ResponseResult.success(authService.getTokenByAuthorizationCode(authCodeDto)); } + + @GetMapping("/qrcode/scan") + @ApiVersion(1) + public ResponseObject qrcodeScan(@RequestParam("k") String k, @RequestParam("f") String f) { + try { + return ResponseResult.success(authService.qrcodeScan(k, f)); + } catch (Exception e) { + throw new AuthRuntimeException(HttpCode.BAD_REQUEST, e.getMessage()); + } + } } diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/dto/AuthorizationDto.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/dto/AuthorizationDto.java index 27e53f9..f1f7e92 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/dto/AuthorizationDto.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/dto/AuthorizationDto.java @@ -1,5 +1,7 @@ package cn.zyjblogs.server.user.dto; +import cn.zyjblogs.server.user.po.OauthUserDetails; +import cn.zyjblogs.starter.common.entity.context.BaseContext; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -98,4 +100,16 @@ public class AuthorizationDto implements Authentication { public void setAuthenticated(Boolean authenticated) { this.authenticated = authenticated; } + + public AuthorizationDto createAuthorization() { + AuthorizationDto authorizationDto = new AuthorizationDto(); + OauthUserDetails oauthUserDetails = new OauthUserDetails(); + oauthUserDetails.setId(BaseContext.getUserId()); + oauthUserDetails.setName(BaseContext.getName()); + oauthUserDetails.setUsername(BaseContext.getUsername()); + oauthUserDetails.setTenantId(BaseContext.getTenantId()); + authorizationDto.setPrincipal(oauthUserDetails); + authorizationDto.setAuthenticated(true); + return authorizationDto; + } } diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/handler/OauthRquestHander.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/handler/OauthRquestHander.java index ec816e4..66b6212 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/handler/OauthRquestHander.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/handler/OauthRquestHander.java @@ -13,13 +13,7 @@ import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; import java.net.URI; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * @author zhuyijun @@ -141,7 +135,7 @@ public class OauthRquestHander { return builder.build().toUriString(); } - private static String append(String base, Map query, boolean fragment) { + public static String append(String base, Map query, boolean fragment) { return append(base, query, (Map) null, fragment); } diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/AuthService.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/AuthService.java index af49817..47e54ef 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/AuthService.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/AuthService.java @@ -39,4 +39,13 @@ public interface AuthService { * @date 2022/10/15 */ OAuth2AccessTokenVo getTokenByAuthorizationCode(AuthCodeDto authCodeDto); + + /** + * 二维码扫码登录 + * + * @param k + * @param f + * @return + */ + Boolean qrcodeScan(String k, String f); } diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/impl/AuthServiceImpl.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/impl/AuthServiceImpl.java index 805bc3d..50f2a01 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/impl/AuthServiceImpl.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/service/impl/AuthServiceImpl.java @@ -1,17 +1,18 @@ package cn.zyjblogs.server.user.service.impl; +import cn.zyjblogs.server.qrcode.dto.QrCode; import cn.zyjblogs.server.user.dto.AuthCodeDto; import cn.zyjblogs.server.user.dto.AuthorizationCodeDto; import cn.zyjblogs.server.user.dto.AuthorizationDto; import cn.zyjblogs.server.user.dto.OAuth2AccessTokenDto; import cn.zyjblogs.server.user.handler.OauthRequestValidator; import cn.zyjblogs.server.user.handler.OauthRquestHander; -import cn.zyjblogs.server.user.po.OauthUserDetails; import cn.zyjblogs.server.user.service.AuthService; import cn.zyjblogs.server.user.vo.OAuth2AccessTokenVo; -import cn.zyjblogs.starter.common.entity.context.BaseContext; +import cn.zyjblogs.starter.common.entity.constant.CommonRedisKeyConstant; import cn.zyjblogs.starter.common.entity.response.HttpCode; import cn.zyjblogs.starter.common.exception.AuthRuntimeException; +import cn.zyjblogs.starter.redis.utils.RedisTemplateHandler; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; @@ -33,6 +34,7 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.util.*; +import java.util.concurrent.TimeUnit; /** * @author zhuyijun @@ -46,11 +48,14 @@ public class AuthServiceImpl implements AuthService { private final PasswordEncoder passwordEncoder; private RedirectResolver redirectResolver; private OauthRequestValidator oauthRequestValidator; + private RedisTemplateHandler redisTemplateHandler; private final Object implicitLock = new Object(); public AuthServiceImpl(AuthorizationServerEndpointsConfiguration authorizationServerEndpointsConfiguration, ClientDetailsService clientDetails, - AuthorizationCodeServices authorizationCodeServices, PasswordEncoder passwordEncoder, OauthRequestValidator oauthRequestValidator) { + AuthorizationCodeServices authorizationCodeServices, PasswordEncoder passwordEncoder, + OauthRequestValidator oauthRequestValidator, + RedisTemplateHandler redisTemplateHandler) { this.tokenGranter = authorizationServerEndpointsConfiguration.getEndpointsConfigurer().getTokenGranter(); this.clientDetails = clientDetails; this.redirectResolver = new DefaultRedirectResolver(); @@ -58,6 +63,7 @@ public class AuthServiceImpl implements AuthService { this.authorizationCodeServices = authorizationCodeServices; this.passwordEncoder = passwordEncoder; this.oauthRequestValidator = oauthRequestValidator; + this.redisTemplateHandler = redisTemplateHandler; } @Value("${security.oauth2.client.client-id}") @@ -139,14 +145,7 @@ public class AuthServiceImpl implements AuthService { if (responseTypes.contains("token")) { return getImplicitGrantResponse(authorizationRequest); } - AuthorizationDto authorizationDto = new AuthorizationDto(); - OauthUserDetails oauthUserDetails = new OauthUserDetails(); - oauthUserDetails.setId(BaseContext.getUserId()); - oauthUserDetails.setName(BaseContext.getName()); - oauthUserDetails.setUsername(BaseContext.getUsername()); - oauthUserDetails.setTenantId(BaseContext.getTenantId()); - authorizationDto.setPrincipal(oauthUserDetails); - authorizationDto.setAuthenticated(true); + AuthorizationDto authorizationDto = new AuthorizationDto().createAuthorization(); try { return OauthRquestHander.getSuccessfulRedirect(authorizationRequest, generateCode(authorizationRequest, authorizationDto)); @@ -179,6 +178,32 @@ public class AuthServiceImpl implements AuthService { } } + @Override + public Boolean qrcodeScan(String k, String f) { + Boolean aBoolean = redisTemplateHandler.hasKey(CommonRedisKeyConstant.QR_CODE + ":" + f + ":" + k); + if (!aBoolean) { + return false; + } + ClientDetails clientDetail = clientDetails.loadClientByClientId(f); + if (clientDetail == null) { + throw new AuthRuntimeException(HttpCode.BAD_REQUEST, "该appid不存在"); + } + Map parameters = new HashMap<>(); + parameters.put("grant_type", "qrcode"); + parameters.put("k", k); + parameters.put("f", f); + TokenRequest tokenRequest = oAuth2RequestFactory.createTokenRequest(parameters, clientDetail); + OAuth2AccessToken token = tokenGranter.grant(tokenRequest.getGrantType(), tokenRequest); + OAuth2AccessTokenVo oAuth2AccessTokenVo = OAuth2AccessTokenVo.TransferToken(token); + QrCode qrCode = QrCode.builder() + .qrsig(k) + .clienId(f) + .token(oAuth2AccessTokenVo) + .build(); + redisTemplateHandler.set(CommonRedisKeyConstant.QR_CODE + ":" + f + ":" + k, qrCode, 5, TimeUnit.MINUTES); + return true; + } + /** * 处理 * diff --git a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/vo/OAuth2AccessTokenVo.java b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/vo/OAuth2AccessTokenVo.java index d523d04..04dd11a 100644 --- a/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/vo/OAuth2AccessTokenVo.java +++ b/server/zyjblogs-oauth/src/main/java/cn/zyjblogs/server/user/vo/OAuth2AccessTokenVo.java @@ -4,7 +4,10 @@ import cn.zyjblogs.starter.common.entity.constant.ContextKeyConstant; import cn.zyjblogs.starter.common.entity.context.BaseContext; import cn.zyjblogs.starter.common.entity.dto.ContextDto; import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import org.springframework.security.oauth2.common.OAuth2AccessToken; import java.io.Serializable; @@ -17,6 +20,9 @@ import java.util.Set; * @author zhuyijun */ @Data +@AllArgsConstructor +@NoArgsConstructor +@Builder public class OAuth2AccessTokenVo implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "access token", dataType = "String", example = "abc.efg.hjk") diff --git a/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/constant/CommonRedisKeyConstant.java b/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/constant/CommonRedisKeyConstant.java index 1ff2d7e..393185f 100644 --- a/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/constant/CommonRedisKeyConstant.java +++ b/stater/zyjblogs-common-spring-boot-starter/src/main/java/cn/zyjblogs/starter/common/entity/constant/CommonRedisKeyConstant.java @@ -18,6 +18,8 @@ public class CommonRedisKeyConstant { */ public static final String XSRF_TOKEN = "XSRF_TOKEN:"; + public static final String QR_CODE = "OAUTH:QR_CODE:"; + private CommonRedisKeyConstant() { } } \ No newline at end of file diff --git a/stater/zyjblogs-oauth-spring-boot-starter/src/main/java/cn/zyjblogs/starter/oauth/resource/ResourceServerConfig.java b/stater/zyjblogs-oauth-spring-boot-starter/src/main/java/cn/zyjblogs/starter/oauth/resource/ResourceServerConfig.java index e47b61d..7fef9c9 100644 --- a/stater/zyjblogs-oauth-spring-boot-starter/src/main/java/cn/zyjblogs/starter/oauth/resource/ResourceServerConfig.java +++ b/stater/zyjblogs-oauth-spring-boot-starter/src/main/java/cn/zyjblogs/starter/oauth/resource/ResourceServerConfig.java @@ -14,6 +14,8 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.R import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.TokenStore; +import java.util.List; + /** * 资源服务 * @@ -44,10 +46,13 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { + List allowPaths = whiteListProperties.getAllowPaths(); + String[] strings = allowPaths.toArray(new String[0]); String scopeRs = "#oauth2.hasAnyScope(" + '\'' + scope + '\'' + ",'all')"; http.csrf().disable() .authorizeRequests() - .antMatchers("/webjars/**", "/swagger-ui.html/**", "/swagger-resources/**", "/v2/api-docs/**", String.join(",", whiteListProperties.getAllowPaths())).permitAll() + .antMatchers(strings).permitAll() + .antMatchers("/webjars/**", "/swagger-ui.html/**", "/swagger-resources/**", "/v2/api-docs/**").permitAll() .antMatchers("/**").access(scopeRs) .anyRequest() .authenticated()