一、在keycloak上创建client(略)
二、client配置
2.1 在token中加入用户属性
2.1.1 先为用户创建属性,如果所有用户都有这个属性,可以设置一个default role,再在role里面添加默认属性,
2.1.2 编辑client,点击mappers
点create创建mappers,
图中Name的值也为org_code,省的乱了,如图配置,即可在token中看到org_code的值了
token的public 的值在这里查看
三、项目配置
我后端原来用的是django但其他厂家都是springboot,唉,但python也没有太好的单点登录框架。
3.1springboot项目
3.1.1前后端不分离
3.1.1.1 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>7.0.0</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-security-adapter</artifactId>
<version>7.0.0</version>
</dependency>
3.1.1.2 添加配置
application.properties
//keycloak验证地址
keycloak.auth-server-url=http://127.0.0.1:8080/auth
keycloak.disable-trust-manager=true
keycloak.principal-attribute=preferred_username
//client秘钥
keycloak.credentials.secret=a96ee0d9-54af-4d0e-bba7-1e0d7cca5ad5
keycloak.public-client=false
//client所属群
keycloak.realm=zhang
//client id
keycloak.resource=InternalSec
keycloak.use-resource-role-mappings=true
keycloakConfig
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class KeycloakConfig {
@Bean
public KeycloakSpringBootConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
KeycloakSecurityConfigurer
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.keycloak.adapters.springsecurity.management.HttpSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
@KeycloakConfiguration
public class KeycloakSecurityConfigurer extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
SimpleAuthorityMapper grantedAuthorityMapper = new SimpleAuthorityMapper();
grantedAuthorityMapper.setPrefix("ROLE_");
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(grantedAuthorityMapper);
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
// return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
return new NullAuthenticatedSessionStrategy();
}
@Bean
@Override
@ConditionalOnMissingBean(HttpSessionManager.class)
protected HttpSessionManager httpSessionManager() {
return new HttpSessionManager();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeRequests()
// /**代表所有路由都由keycloak保护 hasAnyRole设置用有哪些权限的用户可以登录
.antMatchers("/**").hasAnyRole( "1-user","XiangTaiPolice","org_code")
.anyRequest().permitAll()
.and()
.csrf().disable();
}
}
3.1.1.3 获取用户信息
@GetMapping(path = "/hello")
public String customers(Principal principal, HttpServletRequest request,HttpServletResponse response){
KeycloakAuthenticationToken kcToken=(KeycloakAuthenticationToken)principal;
System.out.println(kcToken);
SimpleKeycloakAccount account=(SimpleKeycloakAccount )kcToken.getAccount();
RefreshableKeycloakSecurityContext rc=account.getKeycloakSecurityContext();
System.out.println(rc.getTokenString());
String[] vals=(rc.getTokenString()).split("\\.");
for (int i = 0; i < vals.length; i++) {
if(i==1){
vals[1]=vals[1]+"==";
byte[] a= Base64.decodeBase64(vals[1]);
String b=new String(a);
JSONObject jsonObject = JSONObject.parseObject(b);
String org_code=jsonObject.getString("org_code");
String parent_code=jsonObject.getString("parent_code");
System.out.println(org_code);
System.out.println(parent_code);
}
}
return "index";
}
3.1.2 前后端分离(vue)
前后端分离只需要配置前端即可
3.1.2.1 安装keycloak-js
npm i --save @dsb-norge/vue-keycloak-js
3.1.2.2 使用
main.js
import keycloak from '@dsb-norge/vue-keycloak-js';
Vue.use(keycloak , {
init: {
onLoad: 'login-required',
checkLoginIframe: false
},
config: {
url: 'http://127.0.0.1:8080/auth',
realm: 'zhang',
clientId: 'sjpt'
},
onReady: (keycloak) => {
//获取用户的信息
console.log(222,Vue.prototype.$keycloak.token)
//用户的属性也在里面
keycloak.loadUserProfile().success((data) => {
console.log(data);
});
}
});
request.js
//在拦截器里配置,可全局使用
config.headers.Authorization = `Bearer ${Vue.prototype.$keycloak.token}`
每次请求携带token,有效期为5分钟,后端如何解析token
验证token
import java.util.Base64;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.security.KeyFactory;
final Base64.Decoder decoder = Base64.getDecoder();
final Base64.Encoder encoder = Base64.getEncoder();
byte[] decode = decoder.decode(public key);
X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(decode);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKey pubKey = (RSAPublicKey) keyFactory.generatePublic(keySpecX509);
//最好加个try()catch{}出错即验证错误或token过期
Claims claims = Jwts.parser()
.setSigningKey(pubKey)
.parseClaimsJws(token.getString("token")).getBody();
相关方法
//获取用户信息,可获取用户名,及其属性
keycloak.loadUserProfile()
//退出登录
keycloak.logoutFn()
3.2 ?
未完待续。。。