use*_*378 28 java spring spring-mvc
我使用Spring MVC(4.0.1)作为休息服务的后端和angularjs作为前端.
对我的服务器后端的每个请求都有一个带有会话ID的http-header
我可以使用以下代码在服务器后端读取此标头:
@Autowired
protected HttpServletRequest request;
String xHeader=request.getHeader("X-Auth-Token"); //returns the sessionID from the header
Run Code Online (Sandbox Code Playgroud)
现在我调用此方法getPermission(xHeader)只返回true或false.如果用户存在于我的数据库中,则返回true,否则为false!
我现在想要创建一个具有此行为的过滤器,如果用户有权访问我的控制器,则会检查每个请求!但是如果该方法返回false,它应该发回401错误而不能到达我的控制器!
我该怎么做并创建自己的过滤器?我只使用Java Config而不使用XML.
我想我必须在这里添加过滤器:
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Filter[] getServletFilters() {
MyOwnFilter=new MyOwnFilter();
return new Filter[] {MyOwnFilter};
}
}
Run Code Online (Sandbox Code Playgroud)
are*_*res 31
替代过滤器,您可以使用HandlerInterceptor.
public class SessionManager implements HandlerInterceptor{
// This method is called before the controller
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
String xHeader = request.getHeader("X-Auth-Token");
boolean permission = getPermission(xHeader);
if(permission) {
return true;
}
else {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
// Above code will send a 401 with no response body.
// If you need a 401 view, do a redirect instead of
// returning false.
// response.sendRedirect("/401"); // assuming you have a handler mapping for 401
}
return false;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
Run Code Online (Sandbox Code Playgroud)
然后将此拦截器添加到webmvc配置中.
@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
SessionManager getSessionManager() {
return new SessionManager();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getSessionManager())
.addPathPatterns("/**")
.excludePathPatterns("/resources/**", "/login");
// assuming you put your serve your static files with /resources/ mapping
// and the pre login page is served with /login mapping
}
}
Run Code Online (Sandbox Code Playgroud)
下面是执行您提到的逻辑的过滤器
@WebFilter("/*")
public class AuthTokenFilter implements Filter {
@Override
public void destroy() {
// ...
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String xHeader = ((HttpServletRequest)request).getHeader("X-Auth-Token");
if(getPermission(xHeader)) {
chain.doFilter(request, response);
} else {
request.getRequestDispatcher("401.html").forward(request, response);
}
}
}
Run Code Online (Sandbox Code Playgroud)
你做对了,弹簧配置应该跟随.
public class MyWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Filter[] getServletFilters() {
return new Filter[]{new AuthTokenFilter()};
}
}
Run Code Online (Sandbox Code Playgroud)
Spring 可以使用过滤器,但是他们建议你使用他们的过滤器版本,称为拦截器
http://viralpatel.net/blogs/spring-mvc-interceptor-example/
快速了解它们的工作方式.它们几乎与过滤器完全相同,但设计用于在Spring MVC生命周期内工作.
我假设您正在尝试实现某种基于jwt令牌的OAuth安全性。
如今,有几种方法可以做到这一点,但这是我最喜欢的一种方法:
过滤器的外观如下:
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.filter.GenericFilterBean;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureException;
public class JwtFilter extends GenericFilterBean {
@Override
public void doFilter(final ServletRequest req,
final ServletResponse res,
final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
throw new ServletException("Missing or invalid Authorization header.");
}
final String token = authHeader.substring(7); // The part after "Bearer "
try {
final Claims claims = Jwts.parser().setSigningKey("secretkey")
.parseClaimsJws(token).getBody();
request.setAttribute("claims", claims);
}
catch (final SignatureException e) {
throw new ServletException("Invalid token.");
}
chain.doFilter(req, res);
}
}
Run Code Online (Sandbox Code Playgroud)
很简单,您还可以在用户控制器中找到登录方法:
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
@RestController
@RequestMapping("/user")
public class UserController {
private final Map<String, List<String>> userDb = new HashMap<>();
public UserController() {
userDb.put("tom", Arrays.asList("user"));
userDb.put("sally", Arrays.asList("user", "admin"));
}
@RequestMapping(value = "login", method = RequestMethod.POST)
public LoginResponse login(@RequestBody final UserLogin login)
throws ServletException {
if (login.name == null || !userDb.containsKey(login.name)) {
throw new ServletException("Invalid login");
}
return new LoginResponse(Jwts.builder().setSubject(login.name)
.claim("roles", userDb.get(login.name)).setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256, "secretkey").compact());
}
@SuppressWarnings("unused")
private static class UserLogin {
public String name;
public String password;
}
@SuppressWarnings("unused")
private static class LoginResponse {
public String token;
public LoginResponse(final String token) {
this.token = token;
}
}
}
Run Code Online (Sandbox Code Playgroud)
当然,我们在Main中可以看到滤豆:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@EnableAutoConfiguration
@ComponentScan
@Configuration
public class WebApplication {
@Bean
public FilterRegistrationBean jwtFilter() {
final FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new JwtFilter());
registrationBean.addUrlPatterns("/api/*");
return registrationBean;
}
public static void main(final String[] args) throws Exception {
SpringApplication.run(WebApplication.class, args);
}
}
Run Code Online (Sandbox Code Playgroud)
最后但并非最不重要的是,有一个示例控制器:
import io.jsonwebtoken.Claims;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class ApiController {
@SuppressWarnings("unchecked")
@RequestMapping(value = "role/{role}", method = RequestMethod.GET)
public Boolean login(@PathVariable final String role,
final HttpServletRequest request) throws ServletException {
final Claims claims = (Claims) request.getAttribute("claims");
return ((List<String>) claims.get("roles")).contains(role);
}
}
Run Code Online (Sandbox Code Playgroud)
这是到GitHub的链接,感谢nielsutrecht所做的出色工作,我已经将该项目作为基础,并且运行良好。
| 归档时间: |
|
| 查看次数: |
56930 次 |
| 最近记录: |