转载务必说明出处:https://blog.csdn.net/LiaoHongHB/article/details/84032850
在这里我们以一台服务器和2台客户端做测试,在客户端1进行登陆之后,访问客服端2的时候不需要进行登陆就可访问(类似于淘宝登陆之后,在淘宝网点击天猫链接会发现天猫网已经是登陆状态)
jwt-server代码:
资源服务器:
@Configuration
@EnableWebSecurity
public class SsoSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.csrf().disable();
}
}
认证服务器:
@Configuration
@EnableAuthorizationServer
public class SsoAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client1")
.secret("clientsecret1")
//支持的授权模式(数组类型)
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("all")
.and()
.withClient("client2")
.secret("clientsecret2")
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("all");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(jwtTokenStore()).accessTokenConverter(jwtAccessTokenConverter());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("isAuthenticated()");
}
@Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
//JWT签名
converter.setSigningKey("jwt");
return converter;
}
}
UserDetailService:
@Component
public class SsoUserDetailService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return new User(username,passwordEncoder.encode("123456"),
AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN"));
}
}
Controller:
@RestController
@SessionAttributes("authorizationRequest")
public class SsoApprovalEndpointController {
@RequestMapping({"/oauth/confirm_access"})
public ModelAndView getAccessConfirmation(Map model, HttpServletRequest request) throws Exception {
String template = this.createTemplate(model, request);
if (request.getAttribute("_csrf") != null) {
model.put("_csrf", request.getAttribute("_csrf"));
}
return new ModelAndView(new SsoSpelView(template), model);
}
protected String createTemplate(Map model, HttpServletRequest request) {
String template = TEMPLATE;
if (!model.containsKey("scopes") && request.getAttribute("scopes") == null) {
template = template.replace("%scopes%", "").replace("%denial%", DENIAL);
} else {
template = template.replace("%scopes%", this.createScopes(model, request)).replace("%denial%", "");
}
if (!model.containsKey("_csrf") && request.getAttribute("_csrf") == null) {
template = template.replace("%csrf%", "");
} else {
template = template.replace("%csrf%", CSRF);
}
return template;
}
private CharSequence createScopes(Map model, HttpServletRequest request) {
StringBuilder builder = new StringBuilder("");
Map scopes = (Map)((Map)(model.containsKey("scopes") ? model.get("scopes") : request.getAttribute("scopes")));
Iterator var5 = scopes.keySet().iterator();
while(var5.hasNext()) {
String scope = (String)var5.next();
String approved = "true".equals(scopes.get(scope)) ? " checked" : "";
String denied = !"true".equals(scopes.get(scope)) ? " checked" : "";
String value = SCOPE.replace("%scope%", scope).replace("%key%", scope).replace("%approved%", approved).replace("%denied%", denied);
builder.append(value);
}
builder.append("
");
return builder.toString();
}
private static String CSRF = "";
private static String DENIAL = "";
private static String TEMPLATE = "" +
"" +
" "+
""+
"" +
"";
private static String SCOPE = "%scope%: Approve Deny ";
}
View.class:
public class SsoSpelView implements View {
private final String template;
private final String prefix;
private final SpelExpressionParser parser = new SpelExpressionParser();
private final StandardEvaluationContext context = new StandardEvaluationContext();
private PropertyPlaceholderHelper.PlaceholderResolver resolver;
public SsoSpelView(String template) {
this.template = template;
this.prefix = new RandomValueStringGenerator().generate() + "{";
this.context.addPropertyAccessor(new MapAccessor());
this.resolver = new PropertyPlaceholderHelper.PlaceholderResolver() {
public String resolvePlaceholder(String name) {
Expression expression = parser.parseExpression(name);
Object value = expression.getValue(context);
return value == null ? null : value.toString();
}
};
}
public String getContentType() {
return "text/html";
}
public void render(Map model, HttpServletRequest request, HttpServletResponse response)
throws Exception {
Map map = new HashMap(model);
String path = ServletUriComponentsBuilder.fromContextPath(request).build()
.getPath();
map.put("path", (Object) path==null ? "" : path);
context.setRootObject(map);
String maskedTemplate = template.replace("${", prefix);
PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper(prefix, "}");
String result = helper.replacePlaceholders(maskedTemplate, resolver);
result = result.replace(prefix, "${");
response.setContentType(getContentType());
response.getWriter().append(result);
}
}
client1代码:
application.yml:
server:
port: 5001
servlet:
context-path: /client1
security:
oauth2:
client:
client-id: client1
client-secret: clientsecret1
user-authorization-uri: http://127.0.0.1:5000/server/oauth/authorize
access-token-uri: http://127.0.0.1:5000/server/oauth/token
resource:
jwt:
key-uri: http://127.0.0.1:5000/server/oauth/token_key
index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
sso client2
SSO CLIENT2 DEMO
访问client1
client2代码:
application.yml:
server:
port: 5002
servlet:
context-path: /client2
security:
oauth2:
client:
client-id: client2
client-secret: clientsecret2
user-authorization-uri: http://127.0.0.1:5000/server/oauth/authorize
access-token-uri: http://127.0.0.1:5000/server/oauth/token
resource:
jwt:
key-uri: http://127.0.0.1:5000/server/oauth/token_key
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
sso client2
SSO CLIENT2 DEMO
访问client1
测试:先运行server,然后客户端。
地址栏输入:localhost:5001/client1/index.jsp --->回车键
然后会跳转到:localhost:5000/sever/login
输入用户名和密码:这里为了方便测试,用户名可以随便输,密码必须为123456
点击Login按钮即返回到client1/index.jsp页面
这个时候点击“访问client2”,在不需要登陆的情况下就可以访问到client2/index.jsp页面(即完成单点登陆类似于淘宝登陆天猫)
在client2/index.jsp中访问client1也是不需要登陆就可访问了。