package com.xqlee.config;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* url 拦截器,实现该接口并在实现类上添加注解@Component,将会自动注入spring拦截器
*
* @author xqlee
*
*/
public interface UrlInterceptor extends HandlerInterceptor {
/***
* 需要拦截的url
*
* @return
*/
String[] pathPatterns();
/***
* 排除拦截
*
* @return
*/
String[] excludePathPatterns();
int order();
}
3.获取spring context容器(为了后面动态添加拦截器)
package com.xqlee.config;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
*
* <pre>
* [Summary]
* 获取spring容器
* [Detail]
* TODO
* [Author]
* xqlee
* [Version]
* v1.0
* 2017年3月23日下午8:59:15
* </pre>
*/
@Component
public class SpringUtils implements ApplicationContextAware {
public static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtils.applicationContext == null) {
SpringUtils.applicationContext = applicationContext;
}
}
}
4.继承WebMvcConfigurerAdapter重写配置,动态添加拦截器
package com.xqlee.config;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* 添加自定义的拦截器
*
* @author
*
*/
@Configuration
public class MvcConfigurerAdapter extends WebMvcConfigurerAdapter {
@Autowired
SpringUtils springUtils;
@Override
public void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
@SuppressWarnings("static-access")
Map<String, UrlInterceptor> urlInterceptors = springUtils.applicationContext
.getBeansOfType(UrlInterceptor.class);
if (!StringUtils.isEmpty(urlInterceptors)) {
Set<String> keys = urlInterceptors.keySet();
Iterator<String> it = keys.iterator();
while (it.hasNext()) {
String key = it.next();
UrlInterceptor urlInterceptor = urlInterceptors.get(key);
String[] pathPatterns = urlInterceptor.pathPatterns();
if (pathPatterns == null) {
pathPatterns = new String[] {};
}
String[] excludePathPatterns = urlInterceptor.excludePathPatterns();
if (excludePathPatterns == null) {
excludePathPatterns = new String[] {};
}
registry.addInterceptor(urlInterceptor).addPathPatterns(pathPatterns)
.excludePathPatterns(excludePathPatterns);
}
}
}
}
5.从这里开始,进行spring security相关配置,配置启用spring security
package com.xqlee.security.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll();
}
/**
* 需要拦截的url
*
* @return
*/
public String[] securityMethodUrlPatterns() {
return new String[] { "/security/**" };
}
}
注意:这里的http.authorizeRequests().anyRequest().permitAll();允许所有访问是为了后面自定义拦截器,不使用默认的spring filterpackage com.xqlee.security.service;
import javax.servlet.http.HttpServletRequest;
/**
* spring security 业务处理
*
* @author xqlee
*
*/
public interface SecurityService {
/**
* 获取认证信息
*
* @param httpServletRequest
*/
public void authenticate(HttpServletRequest httpServletRequest);
/**
* 释放认证信息
*/
public void release();
}
package com.xqlee.security.service;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import com.xqlee.security.UserAuthentication;
@Component
public class SecurityServiceimp implements SecurityService {
@Override
public void authenticate(HttpServletRequest httpServletRequest) {
// 通过http请求cookie或者其他方式拿到用户登录后的凭证
String name = httpServletRequest.getParameter("name");
if ("xqlee".equals(name)) {
// 创建一个认证信息实例
// 1.创建当前用户的角色信息
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
// 2.实例创建
Authentication authentication = new UserAuthentication(authorities, name);
authentication.setAuthenticated(true);
// 添加到安全容器
SecurityContextHolder.getContext().setAuthentication(authentication);
}else{
SecurityContextHolder.clearContext();
}
}
@Override
public void release() {
SecurityContextHolder.clearContext();
}
}
这里的认证只是简单的写死了传递一个name参数且值为xqlee才会认证成功并且添加一个ROLE_ADMIN的角色,当然实际应用这里应该去数据库查询认证,做好缓存等操作package com.xqlee.security;
import java.util.Collection;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
/**
* 自定义用户认证
*
* @author xqlee
*
*/
public class UserAuthentication extends AbstractAuthenticationToken {
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
public UserAuthentication(Collection<? extends GrantedAuthority> authorities) {
super(authorities);
}
public UserAuthentication(Collection<? extends GrantedAuthority> authorities, String name) {
super(authorities);
this.name = name;
}
@Override
public Object getCredentials() {
// TODO Auto-generated method stub
return null;
}
@Override
public Object getPrincipal() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getName() {
return name;
}
}
package com.xqlee.security;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import com.xqlee.config.UrlInterceptor;
import com.xqlee.security.config.WebSecurityConfig;
import com.xqlee.security.service.SecurityService;
/**
* spring security安全拦截器
*
* @author xqlee
*
*/
@Component
public class SecurityInterceptor implements UrlInterceptor {
@Autowired
WebSecurityConfig abstractWebSecurityConfig;
@Autowired
SecurityService securityService;
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception arg3)
throws Exception {
// 后置释放认证信息
securityService.release();
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView arg3)
throws Exception {
}
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse arg1, Object arg2)
throws Exception {
System.out.println("---Security:Interceptor--");
// 前置处理认证信息
securityService.authenticate(httpServletRequest);
return true;
}
@Override
public String[] pathPatterns() {
// 配置中获取拦截信息
return abstractWebSecurityConfig.securityMethodUrlPatterns();
}
@Override
public int order() {
return 0;
}
@Override
public String[] excludePathPatterns() {
// TODO Auto-generated method stub
return null;
}
}
拦截器前置调用获取用户信息生成认证信息package com.xqlee.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexCtrl {
@GetMapping("")
public String index() {
return "Welcome Index Page.";
}
@GetMapping("p1")
public String p1() {
return "P1";
}
@GetMapping("login")
public String login() {
return "Login Page";
}
}
package com.xqlee.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SecurityCtrl {
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/security/s1")
public String s1() {
return "s1";
}
@GetMapping("/security/s2")
public String s2() {
return "s2";
}
}
好了言归正传,如何访问到s1的资源呢?如下:
说明:实际应用中这个认证的信息是登录后的令牌并且是加密的,可能是放session中可能是cookie中
http://blog.xqlee.com/article/129.html