相关文章
http://blog.csdn.net/makefriend7/article/details/53490184
http://blog.csdn.net/makefriend7/article/details/53514908
官网文档说明 http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/
这回要去除Security类中的http.csrf().disagbe()了
这个才算是相对安全一点的做法。当然,真正要安全的地方必须加上
requiresChannel().antMatchers("/mysafe/**").requiresSecure();
(关于SSL的介绍我准备再下一篇博客中研究),这篇的例子就不加这个开关了。
既然是完整版,用户的认证当然得采用自定义的方式
//安全类必须实现接口WebSecurityConfigurer 或者扩展WebSecurityConfigurerAdapter这里采用后者
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableWebSecurity//启用Web安全
@ComponentScan
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
private MySavedRequestAwareAuthenticationSuccessHandler authenticationSuccessHandler;
@Autowired
private SessionCsrfTokenRepository sessionCsrfTokenRepository;
@Autowired
private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
////这个函数主要说明登陆框的样式,地址等等(有默认登陆框)
@Override
protected void configure(HttpSecurity http) throws Exception {
// ant通配符说明
//? 匹配任何单字符
// * 匹配0或者任意数量的字符
// ** 匹配0或者更多的目录
http.formLogin()
.successHandler(authenticationSuccessHandler)
.failureHandler(myAuthenticationFailureHandler).and()
.authorizeRequests()
.antMatchers("/login", "/myresource/**").permitAll()
.antMatchers("/system1/**").hasRole("USER1")
.antMatchers("/system2/**").hasRole("USER2")
.antMatchers("/system3/**").hasAnyRole("USER1", "USER2")
.anyRequest().authenticated();//.and()
}
///这个函数主要说明需要认证的用户,密码,以及权限
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new MyUserDetailService());
}
}
如果要支持https代码如下
@Configuration
@EnableWebSecurity//启用Web安全
@ComponentScan
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
private MySavedRequestAwareAuthenticationSuccessHandler authenticationSuccessHandler;
@Autowired
private SessionCsrfTokenRepository sessionCsrfTokenRepository;
@Autowired
private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.successHandler(authenticationSuccessHandler)
.failureHandler(myAuthenticationFailureHandler).and()
.requiresChannel()
.antMatchers("/login").requiresSecure()
.antMatchers("/system1/**").requiresSecure()
.antMatchers("/system2/**").requiresSecure().and()
.authorizeRequests()
.antMatchers("/login", "/myresource/**").permitAll()
.antMatchers("/system1/**").hasRole("USER1")
.antMatchers("/system2/**").hasRole("USER2")
.antMatchers("/system3/**").hasAnyRole("USER1", "USER2")
.anyRequest().authenticated();//.and()
}
///这个函数主要说明需要认证的用户,密码,以及权限
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new MyUserDetailService());
}
失败处理代码如下
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class MyAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
private final static Logger logger = LoggerFactory.getLogger(MyAuthenticationFailureHandler.class);
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
logger.info("认证失败");
JSONObject responseJSONObject = new JSONObject();
responseJSONObject.put("info","login failed");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter out = null;
try {
out = response.getWriter();
out.append(responseJSONObject.toString());
logger.debug("返回是\n");
logger.debug(responseJSONObject.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
}
super.onAuthenticationFailure(request, response, exception);
}
}
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
//这个类可以随便注入,比如读数据库就可以注入数据库的操作类
@Component
public class MyUserDetailService implements UserDetailsService{
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (username.equals("user1")) {
List authorityList = new ArrayList();
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_USER1");
authorityList.add(simpleGrantedAuthority);
User user = new User("user1", "password1", authorityList);
return user;
}
if (username.equals("user2")) {
List authorityList = new ArrayList();
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority("ROLE_USER2");
authorityList.add(simpleGrantedAuthority);
User user = new User("user2", "password2", authorityList);
return user;
}
return null;
}
}
QML客户端的代码比较麻烦。解析XML可以使用XmlListModel,不过这里为了简化处理,直接就取了位置
function myLoginWithCsrf()
{
console.log("begin system fun1");
var url1 = "http://172.16.129.15:8080/system1/fun1";
var tmp1 = JSON;
tmp1.username = "user1"
tmp1.password = "password1";
var mycontent = JSON.stringify(tmp1);
// myhttp.abort();
myhttp.open("POST", url1, false); //简单化处理。都采用同步的方式
myhttp.setRequestHeader("Content-type", "application/json");
myhttp.setRequestHeader("Content-length", mycontent.length);
myhttp.setRequestHeader("Connection", "Keep-Alive");
myhttp.send(mycontent);//结果是非法的请求
console.log("begin test myresource/resource1");
url1 = "http://172.16.129.15:8080/myresource/resource1";
myhttp.open("POST", url1, false); //简单化处理。都采用同步的方式
myhttp.setRequestHeader("Content-type", "application/json");
myhttp.setRequestHeader("Content-length", mycontent.length);
myhttp.setRequestHeader("Connection", "Keep-Alive");
myhttp.send(mycontent);//资源同样失败
//获取login的XML文件
console.log("get login xml");
mycontent="username=user1&password=password1&submit=Login";
url1 = "http://172.16.129.15:8080/login";
myhttp.open("GET", url1, false); //简单化处理。都采用同步的方式
myhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
myhttp.setRequestHeader("Content-length", mycontent.length);
myhttp.setRequestHeader("Connection", "Keep-Alive");
myhttp.send(mycontent);
var docXml = myhttp.responseText;
//此处应该用XmlListModel进行解析
var docToken = docXml.substring(464, 500)
console.log("docToken is " + docToken);
//登陆,并拿到真正的Token
console.log("begin mylogin");
mycontent="username=user1&password=password1&submit=Login";
url1 = "http://172.16.129.15:8080/login";
myhttp.open("POST", url1, false); //简单化处理。都采用同步的方式
myhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
myhttp.setRequestHeader("Content-length", mycontent.length);
myhttp.setRequestHeader("Connection", "Keep-Alive");
myhttp.setRequestHeader("X-CSRF-TOKEN", docToken);
myhttp.send(mycontent);
var docRealToken = myhttp.responseText;
console.log("docRealToken is "+ docRealToken);
console.log("begin test myresource/resource1");
url1 = "http://172.16.129.15:8080/myresource/resource1";
myhttp.open("POST", url1, false); //简单化处理。都采用同步的方式
myhttp.setRequestHeader("Content-type", "application/json");
myhttp.setRequestHeader("Content-length", mycontent.length);
myhttp.setRequestHeader("Connection", "Keep-Alive");
myhttp.setRequestHeader("X-CSRF-TOKEN", docRealToken);
myhttp.send(mycontent); //现在当然成功
console.log("begin system fun1");
url1 = "http://172.16.129.15:8080/system1/fun1";
myhttp.open("POST", url1, false); //简单化处理。都采用同步的方式
myhttp.setRequestHeader("Content-type", "x-www-form-urlencoded");
myhttp.setRequestHeader("Content-length", mycontent.length);
myhttp.setRequestHeader("Connection", "Keep-Alive");
myhttp.setRequestHeader("X-CSRF-TOKEN", docRealToken);
myhttp.send(mycontent); //有权限也没问题。
console.log("22 begin system fun2");
url1 = "http://172.16.129.15:8080/system2/fun2";
myhttp.open("POST", url1, false); //简单化处理。都采用同步的方式
myhttp.setRequestHeader("Content-type", "x-www-form-urlencoded");
myhttp.setRequestHeader("Content-length", mycontent.length);
myhttp.setRequestHeader("Connection", "Keep-Alive");
myhttp.setRequestHeader("X-CSRF-TOKEN", docRealToken);
myhttp.send(mycontent);//没权限肯定啥都拿不到。
//改用用户2登陆
console.log("chaneg to user2")
console.log("get login xml again");
mycontent="username=user1&password=password1&submit=Login";
url1 = "http://172.16.129.15:8080/login";
myhttp.open("GET", url1, false); //简单化处理。都采用同步的方式
myhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
myhttp.setRequestHeader("Content-length", mycontent.length);
myhttp.setRequestHeader("Connection", "Keep-Alive");
myhttp.send(mycontent);
docXml = myhttp.responseText;
docToken = docXml.substring(464, 500)
console.log("docToken again is " + docToken);
console.log("begin mylogin again");
mycontent="username=user2&password=password2&submit=Login";
url1 = "http://172.16.129.15:8080/login";
myhttp.open("POST", url1, false); //简单化处理。都采用同步的方式
myhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
myhttp.setRequestHeader("Content-length", mycontent.length);
myhttp.setRequestHeader("Connection", "Keep-Alive");
myhttp.setRequestHeader("X-CSRF-TOKEN", docToken);
myhttp.send(mycontent);
docRealToken = myhttp.responseText;
console.log("docRealToken "+ docRealToken);
console.log("begin system fun1");
url1 = "http://172.16.129.15:8080/system1/fun1";
myhttp.open("POST", url1, false); //简单化处理。都采用同步的方式
myhttp.setRequestHeader("Content-type", "x-www-form-urlencoded");
myhttp.setRequestHeader("Content-length", mycontent.length);
myhttp.setRequestHeader("Connection", "Keep-Alive");
myhttp.setRequestHeader("X-CSRF-TOKEN", docRealToken);
myhttp.send(mycontent);
console.log("begin system fun1");
url1 = "http://172.16.129.15:8080/system2/fun2";
myhttp.open("POST", url1, false); //简单化处理。都采用同步的方式
myhttp.setRequestHeader("Content-type", "x-www-form-urlencoded");
myhttp.setRequestHeader("Content-length", mycontent.length);
myhttp.setRequestHeader("Connection", "Keep-Alive");
myhttp.setRequestHeader("X-CSRF-TOKEN", docRealToken);
myhttp.send(mycontent);
}