springboot使用spring-security登录认证完整代码,一步一步来,复制就能用,别看那么长就放弃。
解决方法:
1.创建核心配置类,整合spring security
@Configurable
@EnableWebSecurity
public class WebSpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${survey.openUrl}")
private String openUrl;
@Value("${survey.authenticationUrl}")
private String authenticationUrl;
@Autowired
@Qualifier("survetRememberMeService")
RememberMeServices rememberMeServices;
@Autowired
private SimpleAuthenticationProvider simpleAuthenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
List<String> openUrlList=new ArrayList<String>();
if (!openUrl.isEmpty()){
for(String s:openUrl.split(",")){
openUrlList.add(s);
}
}
List<String> authenticationUrllList=new ArrayList<String>();
if (!authenticationUrl.isEmpty()){
for(String s:authenticationUrl.split(",")){
authenticationUrllList.add(s);
}
}
http.cors().and().csrf().disable().exceptionHandling()
.authenticationEntryPoint(new UnauthorizedEntryPoint())
.and().headers()
.frameOptions().disable().and().authorizeRequests()
.antMatchers(authenticationUrllList.toArray(new String[0])).hasAnyRole("NORMAL","SUPERADMIN")//这里要注意了SUPERADMIN指的是数据库存的用户角色是ROLE_SUPERADMIN
.antMatchers(openUrlList.toArray(new String[0])).permitAll()//匹配到的路径不需要验证
.antMatchers("/api/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.usernameParameter("userName").passwordParameter("password")
.loginProcessingUrl("/api/login")
.successHandler(new AjaxAuthSuccessHandler())
.failureHandler(new AjaxAuthFailHandler())
.and()
.logout()
.logoutUrl("/api/logout").logoutSuccessHandler(new AjaxLogoutSuccessHandler()).and().rememberMe().rememberMeServices(rememberMeServices);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
auth.authenticationProvider(simpleAuthenticationProvider);
}
}
2.UnauthorizedEntryPoint类,没有授权的状态下会执行
public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
//这里写没登录时的调整页面地址
}
}
3.AjaxAuthSuccessHandler认证成功后执行
public class AjaxAuthSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
protected final Log logger = LogFactory.getLog(this.getClass());
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
ResultModel rm = new ResultModel(ResultCode.CODE_00000);
ObjectMapper mapper = new ObjectMapper();
response.setStatus(HttpStatus.OK.value());
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
mapper.writeValue(response.getWriter(), rm);
}
}
4.AjaxAuthFailHandler认证失败执行,例如账号密码错误
public class AjaxAuthFailHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
ResultModel rm = new ResultModel(ResultCode.CODE_00014.getCode(), exception.getMessage());
ObjectMapper mapper = new ObjectMapper();
response.setStatus(HttpStatus.OK.value());
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
mapper.writeValue(response.getWriter(), rm);
}
}
5.调用/api/logout接口退出登录后执行,用来清除cookie和应用缓存等操作
public class AjaxLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
Logger logger = LoggerFactory.getLogger(AjaxLogoutSuccessHandler.class);
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
//退出登录清除各个缓存
ResultModel rm = new ResultModel(ResultCode.CODE_00000);
ObjectMapper mapper = new ObjectMapper();
response.setStatus(HttpStatus.OK.value());
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
mapper.writeValue(response.getWriter(), rm);
}
}
6.记住密码处理类,这里可以实现当session过期后刷新页面时可自动登录
@Component
public class SurvetRememberMeService implements RememberMeServices {
Logger logger= LoggerFactory.getLogger(SurvetRememberMeService.class);
public static final String cookieName="survey";
@Override
public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {
logger.info("免登录验证!");
Cookie[] cookies = request.getCookies();
if (SecurityContextHolder.getContext().getAuthentication() == null&&null!=cookies) {
String notoriginal = "";
for (Cookie cookie : cookies) {
if (cookie.getName().equals(this.cookieName)) {
notoriginal = cookie.getValue();
break;
}
}
if (null != notoriginal && !notoriginal.equals("")) {//重新封装好user类认证
//这里代码可参考SimpleAuthenticationProvider类
SecurityContextHolder.getContext().setAuthentication(return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities()));
return SecurityContextHolder.getContext().getAuthentication();// todo 后期要优化成springSecurity要求的provider来验证
} else {
loginFail(request,response);
}
}
}
return null;
}
@Override
public void loginFail(HttpServletRequest request, HttpServletResponse response) {
}
@Override
public void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) {
//登录成功之后可以在这里设置页面的cookie,方便自动登录
}
protected void onLoginFail(HttpServletRequest request, HttpServletResponse response) {
}
}
7.SimpleAuthenticationProvider接收账号密码第一次登录执行
@Component
public class SimpleAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String userName = authentication.getPrincipal().toString();
Designer designer = designerDao.findByEmail(userName);//这里查数据库,designer改成你的用户实体类就好
if (designer == null) {
throw new BadCredentialsException("查无此用户");
}
if (authentication.getCredentials().toString().equals(designer.getPassword())) {
List<GrantedAuthority> auth=new ArrayList<>();
List<String> roles=null;//这里把你的用户的角色add到roles中去
for(String role:roles){
auth.add(new SimpleGrantedAuthority(role));
}
return new UsernamePasswordAuthenticationToken(designer, designer.getPassword(), auth);
} else {
throw new BadCredentialsException("用户名或密码错误。");
}
}
@Override
public boolean supports(Class<?> arg0) {
return true;
}
}
8.登录页面
<form method="post" id="fm1" class="m-form" action="/api/login">
<div class="alert alert-danger" id="errTip" style="display: none;">
<span></span>
</div>
<section class="row">
<div class="m-form-item">
<label><i class="icon-user"></i></label>
<input class="required u-input"
id="username"
name="userName"
size="25"
tabindex="1"
type="text"
autocomplete="on" placeholder="用户名" required/>
</div>
</section>
<section class="row">
<div class="m-form-item">
<label><i class="icon-lock"></i></label>
<input class="required u-input"
type="password"
id="password"
name="password"
size="25"
tabindex="2"
autocomplete="off" placeholder="密码" required/>
<i class="icon-eye"></i>
</div>
</section>
<section class="row btn-row">
<input type="hidden" name="execution"/>
<input type="hidden" name="_eventId" value="submit"/>
<input type="hidden" name="geolocation"/>
<input class="btn u-submit-btn btn-block isLogin"
name="submit"
accesskey="l"
value="登录"
tabindex="6"
type="button" onclick="login()"/>
</section>
</form>
function login() {
$.ajax({
//几个参数需要注意一下
type: "POST",//方法类型
dataType: "json",//预期服务器返回的数据类型
url: "/api/login" ,//url
data: $('#fm1').serialize(),
success: function (result) {
if (result.errorCode == "00000") {
//登陆成功跳转
}else{
}
;
},
error : function() {
}
});
}
9.其他类,希望能帮到你
public enum ResultCode {
/**
* 通用
*/
CODE_00000("00000", "操作成功"),
CODE_00001("00001", "请求失败"),
CODE_00002("00002", "错误的请求方法"),
CODE_00003("00003", "非法的参数字段"),
CODE_00004("00004", "异常抛出"),
CODE_00005("00005", "权限不足"),
CODE_00006("00006", "分页limit参数错误"),
CODE_00007("00007", "分页offset参数错误"),
CODE_00009("00009", "请求过于频繁"),
CODE_00010("00010", "数据已存在"),
CODE_00011("00011", "数据不存在"),
CODE_00012("00012", "参数缺失"),
CODE_00013("00013", "系统维护中"),
CODE_00014("00014", "token缺失"),
CODE_00015("00015", "token失效"),
CODE_00016("00016", "签名错误"),
CODE_10000("10000", "操作部分成功"),
/**
* 系统
*/
CODE_30000("30000", "系统ID错误"),
/**
* 授权
*/
CODE_40001("40001", "用户未找到"),
CODE_40002("40002", "该用户状态异常"),
CODE_40003("40003", "该用户已被删除"),
CODE_40004("40004", "授权异常"),
CODE_99999("99999", "签名无效");
private String code;
private String desc;
ResultCode(String code, String desc) {
this.code = code;
this.desc = desc;
}
public String getCode() {
return code;
}
public String getDesc() {
return desc;
}
/**
* 根据code匹配枚举
*
* @param code
* @return
*/
public static ResultCode getResultCodeByCode(String code) {
for (ResultCode resultCode : ResultCode.values()) {
if (code.equals(resultCode.getCode())) {
return resultCode;
}
}
return null;
}
public static ResultCode getResultCodeByDesc(String desc) {
for (ResultCode resultCode : ResultCode.values()) {
if (desc.equals(resultCode.getDesc())) {
return resultCode;
}
}
return null;
}
}
public class ResultModel {
private String errorCode;
private String message;
private Object data;
public ResultModel(String errorCode, String message) {
this.errorCode = errorCode;
this.message = message;
}
public ResultModel(String errorCode, String message, Object data) {
this.errorCode = errorCode;
this.message = message;
this.data = data;
}
public ResultModel(ResultCode resultCodeEnum, Object data) {
this.errorCode = resultCodeEnum.getCode();
this.message = resultCodeEnum.getDesc();
this.data = data;
}
public ResultModel(ResultCode resultCodeEnum) {
this.errorCode = resultCodeEnum.getCode();
this.message = resultCodeEnum.getDesc();
}
public String geterrorCode() {
return errorCode;
}
public void seterrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}