码上敲享录 > SpringBoot常见问题详解 > springboot使用spring-security登录认证完整代码

springboot使用spring-security登录认证完整代码

上一章章节目录下一章 2020-12-09已有1358人阅读 评论(0)

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;

}

}


向大家推荐《Activiti工作流实战教程》:https://xiaozhuanlan.com/activiti
2

有建议,请留言!

  • *您的姓名:

  • *所在城市:

  • *您的联系电话:

    *您的QQ:

  • 咨询问题:

  • 提 交