для конфигурации Gradle Я предлагаю использовать веб-сайт http://start.spring.io/ и для сервера авторизации. конфигурация будет такой:
buildscript {
ext {
springBootVersion = '2.0.3.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
ext {
springCloudVersion = 'Finchley.RELEASE'
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.cloud:spring-cloud-starter-oauth2')
compile('org.springframework.cloud:spring-cloud-starter-security')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
тогда сервер аутентификации будет выглядеть так:
@Configuration
@EnableAuthorizationServer
public class SecurityOAuth2AutorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private final AccountUserDetailsService accountUserDetailsService;
private final UserDetailsService authenticationManager;
private final PasswordEncoder passwordEncoder;
public SecurityOAuth2AutorizationServerConfig(UserDetailsService accountUserDetailsService,
AuthenticationManager authenticationManager,
PasswordEncoder passwordEncoder) {
this.accountUserDetailsService = accountUserDetailsService;
this.authenticationManager = authenticationManager;
this.passwordEncoder = passwordEncoder;
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.approvalStoreDisabled()
.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter())
.userDetailsService(accountUserDetailsService)
.reuseRefreshTokens(false);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer.tokenKeyAccess("permitAll()")
.passwordEncoder(passwordEncoder)
.checkTokenAccess("isAuthenticated()")
.allowFormAuthenticationForClients();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.secret(passwordEncoder.encode("secret"))
.authorizedGrantTypes("authorization_code", "refresh_token", "password").scopes("openid")
.authorities("ROLE_USER", "ROLE_EMPLOYEE")
.scopes("read", "write", "trust", "openid")
.resourceIds("oauth2-resource")
.autoApprove(true)
.accessTokenValiditySeconds(5)
.refreshTokenValiditySeconds(60*60*8);
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
....
}
}
конфигурация страницы входа в систему для sso будет такой:
@Configuration
@Order(SecurityProperties.DEFAULT_FILTER_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.formLogin()
.permitAll()
.and()
.authorizeRequests().anyRequest().authenticated();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService accountUserDetailsService() {
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
inMemoryUserDetailsManager.createUser(new User("user", "secret",
Collections.singleton(new SimpleGrantedAuthority("USER"))));
return inMemoryUserDetailsManager;
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
В вашем приложении в sso вы можете настроить, как показано ниже:
@EnableOAuth2Sso
@EnableZuulProxy
@SpringBootApplication
public class SsoDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SsoDemoApplication.class, args);
}
@Bean
@Primary
public OAuth2RestTemplate oAuth2RestTemplate(OAuth2ClientContext context,
OAuth2ProtectedResourceDetails authorizationCodeResourceDetails) {
return new OAuth2RestTemplate(authorizationCodeResourceDetails, context);
}
}
в вашем application.yml:
security:
oauth2:
client:
clientId: client
clientSecret: secret
accessTokenUri: http://localhost:9090/auth/oauth/token
userAuthorizationUri: http://localhost:9090/auth/oauth/authorize
auto-approve-scopes: '.*'
registered-redirect-uri: http://localhost:9090/auth/singin
clientAuthenticationScheme: form
resource:
jwt:
key-value: -----BEGIN PUBLIC KEY-----
......
-----END PUBLIC KEY-----
server:
use-forward-headers: true
zuul:
sensitiveHeaders:
ignoredServices: '*'
ignoreSecurityHeaders: false
addHostHeader: true
routes:
your-service: /your-service/**
proxy:
auth:
routes:
spent-budget-service: oauth2
таким образом вы настраиваете свое клиентское приложение в sso с вашим сервером аутентификации, @ EnableOAuth2Sso сделает все для вас, это также как клиентское приложение, и если ваше приложение не аутентифицировано, ваш sso перенаправит вас на страницу входа в систему ваш сервер аутентификации и обновит ваш токен для вас. zuul token relay. Он также доступен как функция в этом случае. Я использую eureka в качестве реестра службы обнаружения. Очень важно настроить OAuth2RestTemplate, потому что Spring будет использовать этот bean-компонент для автоматического обновления вашего токена, в противном случае, как только срок действия вашего токена истечет, вы не сможете автоматически обновить токен.
весь ваш ресурсный сервер будет выглядеть так:
@EnableResourceServer
@SpringBootApplication
public class AccountServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AccountServiceApplication.class, args);
}
}
в вашем application.yml:
security:
oauth2:
resource:
jwt:
key-value: -----BEGIN PUBLIC KEY-----
.....
-----END PUBLIC KEY----
-
конечно, это очень минимальная конфигурация, но для запуска достаточно идентификатора
UPDATE:
не забывайте настройку ресурса в приложении yml на вашем шлюзе, sso и любом другом сервере ресурсов, потому что в противном случае невозможно будет проверить токен на вашем сервере аутентификации.
В случае простого токена oauth2 вы можете использовать
security.oauth2.resource.token-info-uri: your/auth/server:yourport/oauth/check_token
или
security.oauth2.resource.user-info-uri: yourAccountDEtailsRndpoint/userInfo.json
security.oauth2.resource.preferTokenInfo: false
типичная точка входа данных вашей учетной записи на сервере авторизации в случае предпочтения Tokenenfo: false.
@RestController
@RequestMapping("/account")
class UserRestFullEndPoint {
@GetMapping("/userInfo")
public Principal userInfo(Principal principal){
return principal;
}
}
UserInfoRestTemplateFactory в случае, если конфигурация token-info-uri будет предоставлена автоматически к весне, единственное, что нужно помнить, это настроить Oauth2RestTemplate, потому что в противном случае ваш токен больше не будет обновляться
ОБНОВЛЕНИЕ 2
В случае отсутствия токена JWT недостающая конфигурация должна быть добавлена
@EnableResourceServer на вашем сервере аутентификации.
Таким образом, ваша пользовательская информация uri вернет основной объект, например, json. Проблема состояла в том, что ваша конечная точка в любом случае вернет значение NULL, и, следовательно, ваша служба получила 401. Это происходит потому, что ваш сервер аутентификации может только возвращать токен и не может предоставлять другие службы, которые не являются конечной точкой платформы, для обеспечения маркер. Поскольку вам нужно возвращать информацию о пользователе, вам нужен способ предоставления ресурса, и, следовательно, вам необходимо предоставить доступ к серверу авторизации, даже как к серверу ресурсов. В случае jwt это бесполезно, потому что проверка токена и информация о пользователе будет предоставлена самим токеном. Информация о пользователе будет предоставлена jwt и подтверждением с помощью ключа jwt.
резюме вашего сервера авторизации будет выглядеть так:
@SpringBootApplication
public class AuthserverApplication {
public static void main(String[] args) {
SpringApplication.run(AuthserverApplication.class, args);
}
}
@RestController
class UserInfo {
@GetMapping("/account/user-info")
public Principal principal(Principal principal){
System.out.println(principal);
return principal;
}
}
@Controller
class Login{
@GetMapping(value = "/login", produces = "application/json")
public String login(){
return "login";
}
}
@Configuration
@EnableAuthorizationServer
@EnableResourceServer
class SecurityOAuth2AutorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager)
.approvalStoreDisabled()
.reuseRefreshTokens(false)
.userDetailsService(accountUserDetailsService());
}
@Bean
public UserDetailsService accountUserDetailsService() {
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
inMemoryUserDetailsManager.createUser(new User("user", passwordEncoder.encode("secret"),
Collections.singleton(new SimpleGrantedAuthority("USER"))));
return inMemoryUserDetailsManager;
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer.tokenKeyAccess("permitAll()")
.passwordEncoder(passwordEncoder)
.checkTokenAccess("isAuthenticated()")
.allowFormAuthenticationForClients();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.secret(passwordEncoder.encode("secret"))
.authorizedGrantTypes("client_credentials", "password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_USER", "ROLE_EMPLOYEE")
.scopes("read", "write", "trust", "openid")
.autoApprove(true)
.refreshTokenValiditySeconds(20000000)
.accessTokenValiditySeconds(20000000);
}
}
@Configuration
@Order(SecurityProperties.DEFAULT_FILTER_ORDER)
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().httpBasic().disable()
.formLogin().loginPage("/login").loginProcessingUrl("/login")
.permitAll()
.and()
.requestMatchers().antMatchers("/account/userInfo", "/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.authorizeRequests().anyRequest().authenticated();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
страница входа:
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" th:href="@{/webjars/bootstrap/3.3.7-1/css/bootstrap.css}"/>
<link rel="stylesheet" th:href="@{/webjars/bootstrap/3.3.7-1/css/bootstrap-theme.css}"/>
<title>Log In</title>
</head>
<body>
<div class="container">
<form role="form" action="login" method="post">
<div class="row">
<div class="form-group">
<div class="col-md-6 col-lg-6 col-md-offset-2 col-lg-offset-">
<label for="username">Username:</label>
<input type="text" class="form-control" id="username" name="username"/>
</div>
</div>
</div>
<div class="row">
<div class="form-group">
<div class="col-md-6 col-lg-6 col-md-offset-2 col-lg-offset-2">
<label for="password">Password:</label>
<input type="password" class="form-control" id="password" name="password"/>
</div>
</div>
</div>
<div class="row">
<div class="col-md-offset-2 col-lg-offset-2 col-lg-12">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
</div>
<script th:src="@{/webjars/jquery/3.2.0/jquery.min.js}"></script>
<script th:src="@{/webjars/bootstrap/3.3.7-1/js/bootstrap.js}" ></script>
</body>
</html>
application.yml:
server:
use-forward-headers: true
port: 9090
servlet:
context-path: /auth
management.endpoints.web.exposure.include: "*"
spring:
application:
name: authentication-server
ваш сервер sso будет выглядеть так:
@EnableZuulProxy
@SpringBootApplication
public class SsoApplication {
public static void main(String[] args) {
SpringApplication.run(SsoApplication.class, args);
}
@Bean
public OAuth2RestTemplate oAuth2RestTemplate(OAuth2ClientContext context,
OAuth2ProtectedResourceDetails authorizationCodeResourceDetails) {
return new OAuth2RestTemplate(authorizationCodeResourceDetails, context);
}
}
@Configuration
@EnableOAuth2Sso
class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().cors().and().httpBasic().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeRequests().anyRequest().authenticated();
}
}
простая страница на http://localhost:8080/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
It Works by an SSO
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script>
$.ajax({
url: "/hello-service/hello",
success: function (data, status) {
window.alert("The returned data" + data);
}
})
</script>
</body>
</html>
application.yml:
security:
oauth2:
client:
clientId: client
clientSecret: secret
accessTokenUri: http://localhost:9090/auth/oauth/token
userAuthorizationUri: http://localhost:9090/auth/oauth/authorize
auto-approve-scopes: '.*'
registered-redirect-uri: http://localhost:9090/auth/login
clientAuthenticationScheme: form
resource:
user-info-uri: http://localhost:9090/auth/account/user-info
prefer-token-info: false
management.endpoints.web.exposure.include: "*"
server:
use-forward-headers: true
port: 8080
zuul:
sensitiveHeaders:
ignoredServices: '*'
ignoreSecurityHeaders: false
addHostHeader: true
routes:
hello-service:
serviceId: hello-service
path: /hello-service/**
url: http://localhost:4040/
proxy:
auth:
routes:
hello-service: oauth2
Ваш сервис hello (resourceserver) будет:
@SpringBootApplication
public class ResourceServerApplication {
public static void main(String[] args) {
SpringApplication.run(ResourceServerApplication.class, args);
}
}
@RestController
class HelloService {
@GetMapping("/hello")
public ResponseEntity hello(){
return ResponseEntity.ok("Hello World!!!");
}
}
@Configuration
@EnableResourceServer
class SecurityOAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
Я надеюсь, что это может быть полезно для вас