赞
踩
目录
OAuth2AuthenticationProcessingFilter
DefaultUserAuthenticationConverter
传回OAuth2AuthenticationProcessingFilter
@PreAuthorize中hasAuthority怎么获取权限的?
这里因为配置了TokenStore 和JwtAccessTokenConverter ,所以下面解析jwt使用的配置是这个
- @Configuration
- @EnableResourceServer
- @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//激活方法上的 PreAuthorize注解
- public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
- //公钥
- private static final String PUBLIC_KEY = "publickey.txt";
-
- //定义JwtTokenStore,使用jwt令牌
- @Bean
- public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) {
- return new JwtTokenStore(jwtAccessTokenConverter);
- }
- //定义JJwtAccessTokenConverter,使用jwt令牌
- @Bean
- public JwtAccessTokenConverter jwtAccessTokenConverter() {
- JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
- converter.setVerifierKey(getPubKey());
- return converter;
- }
- /**
- * 获取非对称加密公钥 Key
- * @return 公钥 Key
- * */
- private String getPubKey() {
- Resource resource = new ClassPathResource(PUBLIC_KEY);
- try {
- InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream());
- BufferedReader br = new BufferedReader(inputStreamReader);
- return br.lines().collect(Collectors.joining("\n"));
- } catch (IOException ioe) {
- return null;
- }
- }
- //Http安全配置,对每个到达系统的http请求链接进行校验
- @Override
- public void configure(HttpSecurity http) throws Exception {
- //所有请求必须认证通过
- http.authorizeRequests()
- .antMatchers("/v2/api-docs", "/swagger-resources/configuration/ui",
- "/swagger-resources","/swagger-resources/configuration/security",
- "/swagger-ui.html","/webjars/**","/course/courseview/**").permitAll()//针对swagger-ui进行放行
- .anyRequest().authenticated();
- }
- }
- /**
- * 自定义token显示内容
- */
- @Component
- public class CustomUserAuthenticationConverter extends DefaultUserAuthenticationConverter {
- @Autowired
- UserDetailsService userDetailsService;
-
- @Override
- public Map<String, ?> convertUserAuthentication(Authentication authentication) {
- LinkedHashMap response = new LinkedHashMap();
- String name = authentication.getName();
- response.put("user_name", name);
-
- Object principal = authentication.getPrincipal();
- UserJwt userJwt = null;
- if(principal instanceof UserJwt){
- userJwt = (UserJwt) principal;
- }else{
- //refresh_token默认不去调用userdetailService获取用户信息,这里我们手动去调用,得到 UserJwt
- UserDetails userDetails = userDetailsService.loadUserByUsername(name);
- userJwt = (UserJwt) userDetails;
- }
- response.put("name", userJwt.getName());
- response.put("id", userJwt.getId());
- response.put("utype",userJwt.getUtype());
- response.put("userpic",userJwt.getUserpic());
- response.put("companyId",userJwt.getCompanyId());
- if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
- response.put("authorities", AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
- }
-
- return response;
- }
-
-
- }
当已经登录成功,得到token进行请求资源服务器
首先会被
过滤器进行拦截,通过请求header得到JWT token,将token封装到Authorication中
然后调用
的authenticate方法
进行验证解析jwt Token
authenticate会通过Authorization得到jwtToken,并将jwtToken作为参数调用
的loadAuthentication方法
loadAuthentication会调用
的readAccessToken方法,读取解析token中的内容
readAccessToken会调用convertAccessToken,方法体内会调用
经过配置文件中配置的公钥进行解析jwt Token中的内容得到 jwt中 claim的map集合(包含所有jwt的可可视信息,DefaultUserAuthenticationConverter中配置的属性项)
并且将 map集合和jwt Token 作为参数 继续调用JwtAccessTokenConverter的extractAccessToken
extractAccessToken会往下传递调用
的extractAccessToken方法。
进行map集合的数据格式整理,最后封装到
然后传回
接着会将上面传回的OAuth2AccessToken作为参数调用
的readAuthentication方法 进行权限读取。
readAuthentication会将OAuth2AccessToken中的jwt Token取出
进行解析信息后将map传入
extractAuthentication方法
紧接着会像上面过程一样。会将参数传递调用
的extractAuthentication方法
extractAuthentication方法中会将map作为参数传入
的extractAuthentication方法 进行权限封装
2个方法主要作用是判断map中是否有用户名(user_name)和权限(authorities)2个属性。如果没有user_name直接返回为null,反之返回由这2个属性封装好的UsernamePasswordAuthenticationToken。
(可以在配置类配置userDetailsService,配置后可以进行通过loadUserByUserName校验然后更改原有的权限和用户。)
这里需要注意 user_name和authorities是固定好的名字,所以在DefaultUserAuthenticationConverter中需要注意传入jwt claim的参数名。
- public Authentication extractAuthentication(Map<String, ?> map) {
- //检查map中包不包含user_name
- if (map.containsKey("user_name")) {
- Object principal = map.get("user_name");
- Collection<? extends GrantedAuthority> authorities = this.getAuthorities(map);
- if (this.userDetailsService != null) {
- UserDetails user = this.userDetailsService.loadUserByUsername((String)map.get("user_name"));
- authorities = user.getAuthorities();
- principal = user;
- }
-
- return new UsernamePasswordAuthenticationToken(principal, "N/A", authorities);
- } else {
- return null;
- }
- }
- private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map) {
- if (!map.containsKey("authorities")) {
- return this.defaultAuthorities;
- } else {
- Object authorities = map.get("authorities");
- if (authorities instanceof String) {
- return AuthorityUtils.commaSeparatedStringToAuthorityList((String)authorities);
- } else if (authorities instanceof Collection) {
- return AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils.collectionToCommaDelimitedString((Collection)authorities));
- } else {
- throw new IllegalArgumentException("Authorities must be either a String or a Collection");
- }
- }
- }
注意绿字属性名,这里代表有些属性名是固定的。
注意红框部分。这里代表了jwt Token 没有带user_name 也可以,只要jwt Token中包含了authorities属性,然后将Authentication和OAuth2Request封装为OAuth2Authentication依次传回到DefaultTokenServices
这里也需要注意。这个类的ClientDetailsService也是可以配置的,配置后可以进行检验ClientId是否合法
继续传回
最后将用户认证信息设置到SecurityContext中
通过设置请求头方式请求资源服务器,会被OAuth2的OAuth2AuthenticationProcessingFilter过滤器所拦截,通过资源服务配置文件中指定的JwtTokenStore和JwtAccessTokenConverter,使用配置好的公钥进行解析jwt Token得到一系列信息。这里需要注意,如user_name,authorities等属性名已经固定。所以需要在token生成的时候就注意名字规范。最后将封装好的Authorication设置到SecurityContext中。
hasAuthority为SecurityExpressionRoot的方法,此方法会从Authorication中获取authorities集合,并检查hasAuthority中要求的权限是否在集合中。满足要求则执行,否则抛出异常。
经过路径查看可以看出通过Aop的方式在
的beforeInvocation方法传入Authorication一路传递参数,最后初始化SecurityExpressionRoot类
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。