文章目录
涉及到的文件介绍AjaxAccessDeniedHandlerAjaxAuthenticationEntryPointJwtUtilsJwtAuthenticationTokenFilterUrlFilterInvocationSecurityMetadataSourceUrlAccessDecisionManagerSpringSecurityConfig
涉及到的文件介绍
AjaxAccessDeniedHandler----用户权限不足时反给前端的数据 AjaxAuthenticationEntryPoint----用户没登陆时反给前端的数据 JwtAuthenticationTokenFilter----Jwt过滤器(第一个过滤器):获取用户token,查询用户信息拼装到security中,以便后续filter使用 JwtUtils----Jwt工具包 SpringSecurityConfig----Security核心配置文件 UrlAccessDecisionManager----自定义的比较逻辑;根据用户信息和权限去与当前访问的url需要的权限进行对比 UrlFilterInvocationSecurityMetadataSource----这个类是分析得出 用户访问的 url 需要哪些权限 其它关于权限模块的表和bean类我就不记了,用脚都能写出来。 下面是根据用户Id获取用户权限的sql:
SELECT a
.permission
FROM sys_resource a
WHERE a
.id
in (
SELECT resource_id
FROM sys_role_resource
WHERE role_id
in (
SELECT role_id
FROM sys_user_role
WHERE user_id
=
)
)
下面是具体实现代码,无冗余代码,JwtAuthenticationTokenFilter中第40行的方法就是上面那条SQL
AjaxAccessDeniedHandler
import com
.alibaba
.fastjson
.JSON
;
import com
.sonice1024
.hongchen
.common
.response
.ResponseCode
;
import com
.sonice1024
.hongchen
.common
.response
.ResponseResult
;
import org
.springframework
.security
.access
.AccessDeniedException
;
import org
.springframework
.security
.web
.access
.AccessDeniedHandler
;
import org
.springframework
.stereotype
.Component
;
import javax
.servlet
.http
.HttpServletRequest
;
import javax
.servlet
.http
.HttpServletResponse
;
import java
.io
.IOException
;
@Component
public class AjaxAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest
, HttpServletResponse httpServletResponse
, AccessDeniedException e
) throws IOException
{
ResponseResult result
= ResponseResult
.build(ResponseCode
.NO_AUTHORITY
);
httpServletResponse
.setCharacterEncoding("UTF-8");
httpServletResponse
.setHeader("Content-Type", "application/json");
httpServletResponse
.getWriter().write(JSON
.toJSONString(result
));
}
}
AjaxAuthenticationEntryPoint
import com
.alibaba
.fastjson
.JSON
;
import com
.sonice1024
.hongchen
.common
.response
.ResponseCode
;
import com
.sonice1024
.hongchen
.common
.response
.ResponseResult
;
import org
.springframework
.security
.core
.AuthenticationException
;
import org
.springframework
.security
.web
.AuthenticationEntryPoint
;
import org
.springframework
.stereotype
.Component
;
import javax
.servlet
.http
.HttpServletRequest
;
import javax
.servlet
.http
.HttpServletResponse
;
import java
.io
.IOException
;
@Component
public class AjaxAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest
, HttpServletResponse httpServletResponse
, AuthenticationException e
) throws IOException
{
ResponseResult result
= ResponseResult
.build(ResponseCode
.TOKEN_FAIL
);
httpServletResponse
.setCharacterEncoding("UTF-8");
httpServletResponse
.setHeader("Content-Type", "application/json");
httpServletResponse
.getWriter().write(JSON
.toJSONString(result
));
}
}
JwtUtils
import io
.jsonwebtoken
.Claims
;
import io
.jsonwebtoken
.Jwts
;
import io
.jsonwebtoken
.SignatureAlgorithm
;
import org
.apache
.commons
.lang3
.StringUtils
;
import java
.util
.Date
;
public class JwtUtils {
private static final String SUBJECT
= "***";
private static final long EXPIRE
= 1000*60*60*24*3;
private static final String APPSECRET
= "***";
public static String
createJwtToken(String username
){
if(StringUtils
.isBlank(username
)){
return null
;
}
String token
= Jwts
.builder().setSubject(SUBJECT
)
.claim("username", username
)
.setIssuedAt(new Date())
.setExpiration(new Date(System
.currentTimeMillis()+EXPIRE
))
.signWith(SignatureAlgorithm
.HS512
,APPSECRET
)
.compact();
return token
;
}
public static String
getUsername(String token
){
try {
final Claims claims
= Jwts
.parser().setSigningKey(APPSECRET
).parseClaimsJws(token
).getBody();
if (claims
!= null
) return (String
) claims
.get("username");
} catch (Exception e
) {
return null
;
}
return null
;
}
}
JwtAuthenticationTokenFilter
import com
.sonice1024
.hongchen
.entity
.SysUser
;
import com
.sonice1024
.hongchen
.service
.SysUserService
;
import org
.apache
.commons
.lang3
.StringUtils
;
import org
.springframework
.beans
.factory
.annotation
.Autowired
;
import org
.springframework
.security
.authentication
.UsernamePasswordAuthenticationToken
;
import org
.springframework
.security
.core
.authority
.SimpleGrantedAuthority
;
import org
.springframework
.security
.core
.context
.SecurityContextHolder
;
import org
.springframework
.stereotype
.Component
;
import org
.springframework
.web
.filter
.OncePerRequestFilter
;
import javax
.servlet
.FilterChain
;
import javax
.servlet
.ServletException
;
import javax
.servlet
.http
.HttpServletRequest
;
import javax
.servlet
.http
.HttpServletResponse
;
import java
.io
.IOException
;
import java
.util
.ArrayList
;
import java
.util
.List
;
import java
.util
.stream
.Collectors
;
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private SysUserService sysUserService
;
@Override
protected void doFilterInternal(HttpServletRequest request
,
HttpServletResponse response
,
FilterChain chain
) throws ServletException
, IOException
{
String tokenStr
= request
.getHeader("Authorization");
if (StringUtils
.isNotBlank(tokenStr
)) {
String tokenObj
= JwtUtils
.getUsername(tokenStr
);
if (StringUtils
.isNotBlank(tokenObj
)) {
SysUser user
= sysUserService
.getAUserAndPermission(tokenObj
);
if (user
!= null
) {
List
<SimpleGrantedAuthority> authorities
= new ArrayList<>();
if (user
.getPermissions() != null
&& user
.getPermissions().size() > 0) {
authorities
= user
.getPermissions().stream().map(SimpleGrantedAuthority
::new).collect(Collectors
.toList());
}
UsernamePasswordAuthenticationToken authentication
= new UsernamePasswordAuthenticationToken(tokenObj
, "", authorities
);
SecurityContextHolder
.getContext().setAuthentication(authentication
);
}
}
}
chain
.doFilter(request
, response
);
}
}
UrlFilterInvocationSecurityMetadataSource
import com
.sonice1024
.hongchen
.entity
.SysResource
;
import com
.sonice1024
.hongchen
.service
.SysResourceService
;
import org
.springframework
.security
.access
.ConfigAttribute
;
import org
.springframework
.security
.access
.SecurityConfig
;
import org
.springframework
.security
.web
.FilterInvocation
;
import org
.springframework
.security
.web
.access
.intercept
.FilterInvocationSecurityMetadataSource
;
import org
.springframework
.stereotype
.Component
;
import javax
.annotation
.Resource
;
import java
.util
.Collection
;
@Component
public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
@Resource
private SysResourceService sysResourceService
;
@Override
public Collection
<ConfigAttribute> getAttributes(Object o
) throws IllegalArgumentException
{
String requestUrl
= ((FilterInvocation
) o
).getRequestUrl();
SysResource resource
= sysResourceService
.getPermissionByUrl(requestUrl
);
if (resource
!= null
&& resource
.getVerification() == 1) {
return SecurityConfig
.createList(resource
.getPermission());
} else {
return SecurityConfig
.createList("ROLE_ANONYMOUS");
}
}
@Override
public Collection
<ConfigAttribute> getAllConfigAttributes() {
return null
;
}
@Override
public boolean supports(Class
<?> aClass
) {
return true;
}
}
UrlAccessDecisionManager
import org
.springframework
.http
.HttpMethod
;
import org
.springframework
.security
.access
.AccessDecisionManager
;
import org
.springframework
.security
.access
.AccessDeniedException
;
import org
.springframework
.security
.access
.ConfigAttribute
;
import org
.springframework
.security
.authentication
.InsufficientAuthenticationException
;
import org
.springframework
.security
.core
.Authentication
;
import org
.springframework
.security
.core
.GrantedAuthority
;
import org
.springframework
.security
.core
.context
.SecurityContextHolder
;
import org
.springframework
.security
.web
.FilterInvocation
;
import org
.springframework
.stereotype
.Component
;
import java
.util
.Collection
;
@Component
public class UrlAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication
, Object o
, Collection
<ConfigAttribute> collection
) throws AccessDeniedException
, InsufficientAuthenticationException
{
FilterInvocation fi
= (FilterInvocation
) o
;
if (HttpMethod
.OPTIONS
.name().equals(fi
.getRequest().getMethod())) {
return;
}
for (ConfigAttribute attribute
: collection
) {
if (!"ROLE_ANONYMOUS".equals(attribute
.toString())) {
Object principal
= SecurityContextHolder
.getContext().getAuthentication().getPrincipal();
if (principal
== null
) throw new AccessDeniedException("expire");
Collection
<? extends GrantedAuthority> authorities
= authentication
.getAuthorities();
for (GrantedAuthority authority
: authorities
) {
if (authority
.getAuthority().equals(attribute
.getAttribute())) {
return;
}
}
throw new AccessDeniedException("not allow");
}
}
}
@Override
public boolean supports(ConfigAttribute configAttribute
) {
return true;
}
@Override
public boolean supports(Class
<?> aClass
) {
return true;
}
}
SpringSecurityConfig
import org
.springframework
.beans
.factory
.annotation
.Autowired
;
import org
.springframework
.context
.annotation
.Configuration
;
import org
.springframework
.http
.HttpMethod
;
import org
.springframework
.security
.config
.annotation
.ObjectPostProcessor
;
import org
.springframework
.security
.config
.annotation
.web
.builders
.HttpSecurity
;
import org
.springframework
.security
.config
.annotation
.web
.configuration
.WebSecurityConfigurerAdapter
;
import org
.springframework
.security
.config
.http
.SessionCreationPolicy
;
import org
.springframework
.security
.web
.access
.intercept
.FilterSecurityInterceptor
;
import org
.springframework
.security
.web
.authentication
.UsernamePasswordAuthenticationFilter
;
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
AjaxAuthenticationEntryPoint authenticationEntryPoint
;
@Autowired
AjaxAccessDeniedHandler accessDeniedHandler
;
@Autowired
private JwtAuthenticationTokenFilter jwtRequestFilter
;
@Autowired
UrlAccessDecisionManager urlAccessDecisionManager
;
@Autowired
UrlFilterInvocationSecurityMetadataSource urlFilterInvocationSecurityMetadataSource
;
@Override
protected void configure(HttpSecurity http
) throws Exception
{
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy
.STATELESS
)
.and().authorizeRequests()
.antMatchers(HttpMethod
.OPTIONS
, "/**").permitAll()
.anyRequest().authenticated() // 其它的全部自定义验证
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O
extends FilterSecurityInterceptor> O
postProcess(O o
) {
o
.setAccessDecisionManager(urlAccessDecisionManager
);
o
.setSecurityMetadataSource(urlFilterInvocationSecurityMetadataSource
);
return o
;
}
});
http
.headers().cacheControl();//http的cache控制,如下这句代码会禁用cache
http
.addFilterBefore(jwtRequestFilter
, UsernamePasswordAuthenticationFilter
.class);//添加JWT身份认证的filter
//添加自定义未授权的处理器
http
.exceptionHandling().accessDeniedHandler(accessDeniedHandler
);
//添加自定义未登录的处理器
http
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint
);
}
}
有兴趣交流的可以关注公众号或加我的QQ群: