前面已经完成了Oauth2服务器的开发,简单测试了下access_token的获取。spring security oauth还支持SSO单点登录服务端与客户端。我们现在做的是用户系统,调整一下代码,做SSO服务端。
授权页面
增加一个授权页面,在用户在别的系统中登录的时候询问用户是否允许系统向用户系统取某些信息。
授权
程序想要请您授权以下内容:
请许可上述授权范围并点击确认并授权按钮继续。
授权控制器
在com.biboheart.huip.user.security.controller创建SecurityController.java文件。主要实现用户信息获取,用户权限获取等接口。授权页面的控制器也放在这里
package com.biboheart.huip.user.security.controller;
import java.security.Principal;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.approval.Approval;
import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import com.biboheart.brick.model.BhResponseResult;
@Controller
@SessionAttributes("authorizationRequest")
public class SecurityController {
@Autowired
private ApprovalStore approvalStore;
@RequestMapping(value = "/user/info")
@ResponseBody
public ResponseEntity> user(Principal principal) {
return new ResponseEntity<>(principal, HttpStatus.OK);
}
@RequestMapping(value = "/user/name")
@ResponseBody
public String username(Principal principal) {
return principal.getName();
}
@RequestMapping(value = "/user/authorities")
@ResponseBody
public BhResponseResult> authorities(Principal principal) {
Collection extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
return new BhResponseResult<>(0, "操作成功", authorities);
}
@RequestMapping("/oauth/confirm_access")
public ModelAndView getAccessConfirmation(Map model, Principal principal) {
AuthorizationRequest clientAuth = (AuthorizationRequest) model.remove("authorizationRequest");
model.put("auth_request", clientAuth);
model.put("client", "client");
Map scopes = new LinkedHashMap();
for (String scope : clientAuth.getScope()) {
scopes.put(OAuth2Utils.SCOPE_PREFIX + scope, "false");
}
for (Approval approval : approvalStore.getApprovals(principal.getName(), "client")) {
if (clientAuth.getScope().contains(approval.getScope())) {
scopes.put(OAuth2Utils.SCOPE_PREFIX + approval.getScope(),
approval.getStatus() == ApprovalStatus.APPROVED ? "true" : "false");
}
}
model.put("scopes", scopes);
System.out.println(model);
return new ModelAndView("access_confirmation", model);
}
}
调整配置
SecurityConfiguration.java中增加放行的point
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/", "/home", "/oauth/token", "/oauth/authorize").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
http.addFilterBefore(mobileCodeAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
// @formatter:on
}
修改AuthorizationServerConfiguration
package com.biboheart.huip.user.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
private TokenStore tokenStore;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.secret(new BCryptPasswordEncoder().encode("secret"))
.authorizedGrantTypes("client_credentials", "password", "refresh_token", "authorization_code")
.scopes("all", "user_info")
.autoApprove(false) // true: 不会跳转到授权页面
.redirectUris("http://localhost:8080/login");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(this.authenticationManager)
.tokenStore(tokenStore);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Bean
public ApprovalStore approvalStore() {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
如果autoApprove设置为true的话,客户端就不会进入用户授权页面。对于本系统的客户端就不需要用户确认授权操作,这时候设置为true就行。现在我们是要测试授权页面的。所以设置为false
创建客户端
创建项目dssoclient,因为这个项目源码是不上传的,所以把项目中每个文件的代码都会贴入。
目录结构:
pom.xml
4.0.0
com.biboheart.demos
bootparent
0.0.1-SNAPSHOT
dssoclient
dssoclient
http://maven.apache.org
UTF-8
org.springframework.boot
spring-boot-starter-security
org.springframework.security.oauth
spring-security-oauth2
2.3.3.RELEASE
org.springframework.security.oauth.boot
spring-security-oauth2-autoconfigure
2.0.0.RELEASE
org.springframework.boot
spring-boot-starter-thymeleaf
DssoclientApplication
package com.biboheart.demo.dssoclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DssoclientApplication {
public static void main(String[] args) {
SpringApplication.run(DssoclientApplication.class, args);
}
}
SecurityConfiguration
package com.biboheart.demo.dssoclient.security;
import java.util.Arrays;
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.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.AccessTokenProviderChain;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
@Configuration
@EnableOAuth2Sso
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private OAuth2ClientContext oauth2ClientContext;
@Bean
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ProtectedResourceDetails resource) {
OAuth2RestTemplate template = new OAuth2RestTemplate(resource, oauth2ClientContext);
AuthorizationCodeAccessTokenProvider authCodeProvider = new AuthorizationCodeAccessTokenProvider();
authCodeProvider.setStateMandatory(false);
AccessTokenProviderChain provider = new AccessTokenProviderChain(Arrays.asList(authCodeProvider));
template.setAccessTokenProvider(provider);
return template;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout().permitAll()
.and()
.httpBasic().disable();
// @formatter:on
}
}
HelloController
package com.biboheart.demo.dssoclient.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class HelloController {
@RequestMapping(value = { "/", "/home" }, method = RequestMethod.GET)
public String homePage() {
return "index";
}
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() {
return "hello";
}
}
application.yml
server:
port: 8080
spring:
output:
ansi:
enabled: DETECT
http:
encoding:
charset: UTF-8
multipart:
maxFileSize: -1
maxRequestSize: 100MB
security:
oauth2:
client:
clientId: client
clientSecret: secret
accessTokenUri: http://192.168.2.105:8180/oauth/token
userAuthorizationUri: http://192.168.2.105:8180/oauth/authorize
#tokenName: access_token
#authenticationScheme: query
#clientAuthenticationScheme: form
#以下两行为自定义回调地址
#pre-established-redirect-uri: http://localhost:8080/hello
#use-current-uri: false
resource:
userInfoUri: http://192.168.2.105:8180/user/info
#tokenInfoUri: http://192.168.2.105:8180/oauth/check_token
#prefer-token-info: false
basic:
enabled: false
# LOGGING
logging:
level:
root: info
index.html
Spring Security入门
欢迎使用Spring Security!
点击 这里 打个招呼吧
hello.html
Hello World!
Hello world!
login.html没有使用
测试项目
运行用户系统(服务端项目)
运行dssoclient项目(客户端项目)
访问http://localhost:8080 客户端项目的首页,首页不受控制
点击“这里”,跳转服务端的登录页面
选择一种登录方式后,进入授权页面
许可后点击确认并授权,完成后进入hello页面