添加oauth2单点登录功能

This commit is contained in:
macro
2019-10-25 17:08:42 +08:00
parent ffa4ce5450
commit 8c22ba0f2f
18 changed files with 508 additions and 86 deletions

31
mall-oauth/.gitignore vendored Normal file
View File

@@ -0,0 +1,31 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
### VS Code ###
.vscode/

60
mall-oauth/pom.xml Normal file
View File

@@ -0,0 +1,60 @@
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.macro.mall</groupId>
<artifactId>mall-oauth</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mall-oauth</name>
<description>mall-oauth project for mall</description>
<parent>
<groupId>com.macro.mall</groupId>
<artifactId>mall</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.macro.mall</groupId>
<artifactId>mall-mbg</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.6.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,13 @@
package com.macro.mall;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MallOauthApplication {
public static void main(String[] args) {
SpringApplication.run(MallOauthApplication.class, args);
}
}

View File

@@ -0,0 +1,69 @@
package com.macro.mall.config;
import com.macro.mall.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.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;
/**
* 认证服务器配置
* Created by macro on 2019/9/30.
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserService userService;
@Autowired
@Qualifier("jwtTokenStore")
private TokenStore tokenStore;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
/**
* 使用密码模式需要配置
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager)
.userDetailsService(userService)
.tokenStore(tokenStore) //配置令牌存储策略
.accessTokenConverter(jwtAccessTokenConverter);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("mall-portal")
.secret(passwordEncoder.encode("123456"))
.accessTokenValiditySeconds(3600)
.refreshTokenValiditySeconds(864000)
.redirectUris("http://localhost:8201/mall-portal/login") //单点登录时配置
.autoApprove(true) //自动授权配置
.scopes("all")
.authorizedGrantTypes("authorization_code","password","refresh_token");
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security.tokenKeyAccess("isAuthenticated()"); // 获取密钥需要身份认证,使用单点登录时必须配置
}
}

View File

@@ -0,0 +1,27 @@
package com.macro.mall.config;
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;
/**
* 使用Jwt存储token的配置
* Created by macro on 2019/10/8.
*/
@Configuration
public class JwtTokenStoreConfig {
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
accessTokenConverter.setSigningKey("test_key");//配置JWT使用的秘钥
return accessTokenConverter;
}
}

View File

@@ -0,0 +1,15 @@
package com.macro.mall.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* MyBatis配置类
* Created by macro on 2019/4/8.
*/
@Configuration
@EnableTransactionManagement
@MapperScan({"com.macro.mall.mapper"})
public class MyBatisConfig {
}

View File

@@ -0,0 +1,25 @@
package com.macro.mall.config;
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;
/**
* 资源服务器配置
* Created by macro on 2019/9/30.
*/
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.requestMatchers()
.antMatchers("/user/**");
}
}

View File

@@ -0,0 +1,44 @@
package com.macro.mall.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* SpringSecurity配置
* Created by macro on 2019/10/8.
*/
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeRequests()
.antMatchers("/oauth/**", "/login/**", "/logout/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();
}
}

View File

@@ -0,0 +1,29 @@
package com.macro.mall.controller;
import cn.hutool.core.util.StrUtil;
import io.jsonwebtoken.Jwts;
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;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
/**
* Created by macro on 2019/9/30.
*/
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/getCurrentUser")
public Object getCurrentUser(Authentication authentication, HttpServletRequest request) {
String header = request.getHeader("Authorization");
String token = StrUtil.subAfter(header, "bearer ", false);
return Jwts.parser()
.setSigningKey("test_key".getBytes(StandardCharsets.UTF_8))
.parseClaimsJws(token)
.getBody();
}
}

View File

@@ -0,0 +1,61 @@
package com.macro.mall.domain;
import com.macro.mall.model.UmsMember;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Arrays;
import java.util.Collection;
/**
* 会员详情封装
* Created by macro on 2018/8/3.
*/
public class MemberDetails implements UserDetails {
private UmsMember umsMember;
public MemberDetails(UmsMember umsMember) {
this.umsMember = umsMember;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
//返回当前用户的权限
return Arrays.asList(new SimpleGrantedAuthority("TEST"));
}
@Override
public String getPassword() {
return umsMember.getPassword();
}
@Override
public String getUsername() {
return umsMember.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return umsMember.getStatus()==1;
}
public UmsMember getUmsMember() {
return umsMember;
}
}

View File

@@ -0,0 +1,34 @@
package com.macro.mall.service;
import com.macro.mall.domain.MemberDetails;
import com.macro.mall.mapper.UmsMemberMapper;
import com.macro.mall.model.UmsMember;
import com.macro.mall.model.UmsMemberExample;
import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.util.CollectionUtils;
import java.util.List;
/**
* Created by macro on 2019/9/30.
*/
@Service
public class UserService implements UserDetailsService {
@Autowired
private UmsMemberMapper memberMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UmsMemberExample example = new UmsMemberExample();
example.createCriteria().andUsernameEqualTo(username);
List<UmsMember> memberList = memberMapper.selectByExample(example);
if (!CollectionUtils.isEmpty(memberList)) {
return new MemberDetails(memberList.get(0));
}
throw new UsernameNotFoundException("用户名或密码错误");
}
}

View File

@@ -0,0 +1,35 @@
server:
port: 9401
spring:
application:
name: mall-oauth
datasource:
url: jdbc:mysql://localhost:3306/mall?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: root
druid:
initial-size: 5 #连接池初始化大小
min-idle: 10 #最小空闲连接数
max-active: 20 #最大连接数
web-stat-filter:
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" #不统计这些请求数据
stat-view-servlet: #访问监控网页的登录用户名和密码
login-username: druid
login-password: druid
mybatis:
mapper-locations:
- classpath:dao/*.xml
- classpath*:com/**/mapper/*.xml
management: #开启SpringBoot Admin的监控
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
eureka:
client:
service-url:
defaultZone: http://localhost:8001/eureka/

View File

@@ -0,0 +1,16 @@
package com.macro.mall;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MallOauthApplicationTests {
@Test
public void contextLoads() {
}
}

View File

@@ -33,10 +33,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--mongodb依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -60,6 +56,14 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
</dependencies>
<build>

View File

@@ -2,6 +2,7 @@ package com.macro.mall.portal;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient

View File

@@ -1,113 +1,56 @@
package com.macro.mall.portal.config;
import com.macro.mall.model.UmsMember;
import com.macro.mall.portal.component.*;
import com.macro.mall.portal.domain.MemberDetails;
import com.macro.mall.portal.service.UmsMemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.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.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* SpringSecurity的配置
* Created by macro on 2018/8/3.
* 单点登录资源服务器配置
* Created by macro on 2019/10/25.
*/
@Configuration
@EnableWebSecurity
@EnableOAuth2Sso
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UmsMemberService memberService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.GET, // 允许对于网站静态资源的无授权访问
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/swagger-resources/**",
"/v2/api-docs/**",
"/webjars/springfox-swagger-ui/**"
)
.permitAll()
// .antMatchers(HttpMethod.GET, // 允许对于网站静态资源的无授权访问
// "/",
// "/*.html",
// "/favicon.ico",
// "/**/*.html",
// "/**/*.css",
// "/**/*.js",
// "/swagger-resources/**",
// "/v2/api-docs/**",
// "/webjars/springfox-swagger-ui/**"
// )
// .permitAll()
.antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求
.permitAll()
.antMatchers(
"/sso/*",//登录注册
"/home/**"//首页接口
"/home/**",//首页接口
"/actuator/**"//允许SpringBoot Admin 访问监控信息
)
.permitAll()
.antMatchers("/member/**","/returnApply/**")// 测试时开启
.permitAll()
.antMatchers("/actuator/**")// 允许SpringBoot Admin 访问监控信息
.permitAll()
.anyRequest()// 除上面外的所有请求全部需要鉴权认证
.authenticated()
.and()
.exceptionHandling()
.accessDeniedHandler(new GoAccessDeniedHandler())
.authenticationEntryPoint(new GoAuthenticationEntryPoint())
.and()
.formLogin()
.loginPage("/sso/login")
.successHandler(new GoAuthenticationSuccessHandler())
.failureHandler(new GoAuthenticationFailureHandler())
.and()
.logout()
.logoutUrl("/sso/logout")
.logoutSuccessHandler(new GoLogoutSuccessHandler())
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
// .and()
// .requiresChannel()
// .antMatchers("/sso/*")
// .requiresSecure()
// .anyRequest()
// .requiresInsecure()
// .and()
// .rememberMe()
// .tokenValiditySeconds(1800)
// .key("token_key")
.and()
.csrf()
.disable();//开启basic认证登录后可以调用需要认证的接口
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService())
.passwordEncoder(passwordEncoder());
.disable();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService() {
//获取登录用户信息
return new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UmsMember member = memberService.getByUsername(username);
if(member!=null){
return new MemberDetails(member);
}
throw new UsernameNotFoundException("用户名或密码错误");
}
};
}
}

View File

@@ -15,6 +15,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@@ -127,8 +128,8 @@ public class UmsMemberServiceImpl implements UmsMemberService {
public UmsMember getCurrentMember() {
SecurityContext ctx = SecurityContextHolder.getContext();
Authentication auth = ctx.getAuthentication();
MemberDetails memberDetails = (MemberDetails) auth.getPrincipal();
return memberDetails.getUmsMember();
String username = (String) auth.getPrincipal();
return getByUsername(username);
}
@Override

View File

@@ -1,5 +1,9 @@
server:
port: 8085
servlet:
session:
cookie:
name: MALL-PORTAL-SESSIONID
spring:
datasource:
url: jdbc:mysql://localhost:3306/mall?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
@@ -42,6 +46,17 @@ mybatis:
mapper-locations:
- classpath:dao/*.xml
- classpath*:com/**/mapper/*.xml
mall-oauth-url: http://localhost:8201/mall-oauth #认证服务器地址
security:
oauth2: #与oauth2-server对应的配置
client:
client-id: mall-portal
client-secret: 123456
user-authorization-uri: ${mall-oauth-url}/oauth/authorize
access-token-uri: ${mall-oauth-url}/oauth/token
resource:
jwt:
key-uri: ${mall-oauth-url}/oauth/token_key
management: #开启SpringBoot Admin的监控
endpoints:
web:
@@ -63,4 +78,3 @@ rabbitmq:
queue:
name:
cancelOrder: cancelOrderQueue