Series directory
preface
After writing the last article, I studied it for a long time. In the end, I found that JWT seemed inappropriate for our project. Unlike Vue, Layui can not set tokens globally through Axios (maybe I don’t know how to set tokens globally because I like layui). Here is a brief introduction to the front-end operation (vUE as an example), mainly is to get the token after it is stored in localstorage or cookies, and then get the token from localstorage or cookies to set the global request header, it is ok. However, there is no problem with the content of JWT in the previous article, and normal use is also the same step.
The specific content
Remove the JWT
So since you’re not going to use JWT anymore, go back to using cookies and sessions. So we need to get our program back to where it was at the end of Field five.
Here is not very good explains, is to delete related to JWT, need to modify the place has MyAuthenticationSuccessHandler, JwtAuthenticationTokenFilter, SpringSecurityConfig three places, Delete the JWT content. (Not much space)
Front-end Prompt
I’ve modified the login page to give you a message if the login fails
<! DOCTYPEhtml>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="/PearAdmin/admin/css/pearForm.css" />
<link rel="stylesheet" href="/PearAdmin/component/layui/css/layui.css" />
<link rel="stylesheet" href="/PearAdmin/admin/css/pearButton.css" />
<link rel="stylesheet" href="/PearAdmin/assets/login.css" />
</head>
<body background="PearAdmin/admin/images/background.svg" >
<form class="layui-form" method="get">
<div class="layui-form-item">
<img class="logo" src="PearAdmin/admin/images/logo.png" />
<div class="title">M-S-P Admin</div>
<div class="desc">Spring Security's entitlement management system is a real war</div>
</div>
<div class="layui-form-item">
<input id="username" name="username" placeholder=Account name: type="text" hover class="layui-input" required lay-verify="username"/>
</div>
<div class="layui-form-item">
<input id="password" name="password" placeholder="Key code:" type="password" hover class="layui-input" required lay-verify="password"/>
</div>
<div class="layui-form-item">
<input id="captcha" name="captcha" placeholder="Verification Code :" type="text" hover class="layui-verify" style="border: 1px solid #dcdfe6;" required lay-verify="captcha">
<img id="captchaImg" src="/captcha" width="130px" height="44px" onclick="this.src=this.src+'? '+Math.random()" title="Hit Refresh"/>
</div>
<div class="layui-form-item">
<input type="checkbox" id="rememberme" name="rememberme" title="Remember the password" lay-skin="primary" checked>
</div>
<div class="layui-form-item">
<button style="background-color: #5FB878! important;" class="pear-btn pear-btn-primary login" lay-submit lay-filter="formLogin">Insert into</button>
</div>
</form>
<script src="/PearAdmin/component/layui/layui.js" charset="utf-8"></script>
<script>
layui.use(['form'.'element'.'jquery'].function() {
var form = layui.form;
var element = layui.element;
var $ = layui.jquery;
// $("body").on("click",".login",function(obj){
// location.href="/api/admin"
// })
form.verify({
username: function(value) {
if (value.length <= 0 ) {
return 'User name cannot be empty'; }},password: function (value) {
if (value.length <= 0) {
return 'Password cannot be empty'; }},captcha: function (value) {
if (value.length <= 0) {
return 'Captcha cannot be null';
}
if(value.length ! = =4) {
return 'Please enter a captcha in the correct format';
}
}
})
form.on('submit(formLogin)'.function() {
$.ajax({
url:'/login'.type:'post'.dataType:'text'.data: {username: $('#username').val(),
password: $('#password').val(),
captcha: $('#captcha').val(),
rememberme: $('#rememberme').val()
},
success:function(result){
var restjson = JSON.parse(result)
if (restjson.success) {
// layui.data("token", {
// key: "Authorization",
// value: "Bearer "+ restjson.jwt
// });
layer.msg(restjson.msg,{icon:1.time:1000},function () {
location.href = "/";
});
}else {
layer.msg(restjson.msg,{icon:2.time:1000},function () {$("#captchaImg").attr("src"."/captcha" + "?" + Math.random());
});
return false; }}})return false;
});
})
</script>
</body>
</html>
Copy the code
The back end also made a failed login handler
/ * * *@author codermy
* @createTime2020/8/2 * /
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setCharacterEncoding("utf-8");// Change the encoding format
httpServletResponse.setContentType("application/json");
httpServletResponse.getWriter().write(JSON.toJSONString(Result.error().message(e.getMessage())));// Return information}}Copy the code
AuthenticationFailureHandler exception class is an abstract, his common subclass
UsernameNotFoundException users find BadCredentialsException bad credentials AccountStatusException abnormal state it contains the following subclasses AccountExpiredException account overdue LockedException account lock DisabledException account unavailable CredentialsExpiredException certificate has expiredCopy the code
All are exceptions that the user may encounter when logging in
Modified SpringSecurityConfig complete
/ * * *@author codermy
* @createTime2020/7/15 * /
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private VerifyCodeFilter verifyCodeFilter;// Captcha interceptor
@Autowired
MyAuthenticationSuccessHandler authenticationSuccessHandler;// Logon success logic
@Autowired
private MyAuthenticationFailureHandler authenticationFailureHandler;Logon failure logic
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;/ / JWT interceptors
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;// No permission interceptor
@Autowired
private RestfulAccessDeniedHandler accessDeniedHandler;// Have no access to jSON-formatted data
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.GET,
"/swagger-resources/**"."/PearAdmin/**"."/**/*.html"."/**/*.css"."/**/*.js"."/swagger-ui.html"."/webjars/**"."/v2/**");// Permits static resources
}
/ * * * anyRequest | match all the access request path * | SpringEl expression results when they can access to true * anonymous | anonymous access to * denyAll | users cannot access * FullyAuthenticated | user authentication can access fully (not remember - automatic login under me) * hasAnyAuthority | if you have parameters, parametric representation rights, have access any one can access * hasAnyRole | if there is a parameter, Parameters according to role, then any one role can access * hasAuthority | if you have parameters, parameter access, is it can access * hasIpAddress | if you have parameters, parameter indicates the IP address, if the user IP and matching parameters, Can access * hasRole | if you have parameters, parameter, Its role can access * permitAll | users can access any * rememberMe | allow authenticated by remember - me login user access * | accessible * / after the user login
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(verifyCodeFilter, UsernamePasswordAuthenticationFilter.class);
http.csrf().disable()/ / close CSRF
//.sessionManagement(
// .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// .and()
.httpBasic().authenticationEntryPoint(restAuthenticationEntryPoint)// Return data in JSON format to the front-end when not logged in
.and()
.authorizeRequests()
.antMatchers("/captcha").permitAll()// Anyone can access this request
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.html")// Access to the login page is not restricted
.loginProcessingUrl("/login")// Intercepting the request
.successHandler(authenticationSuccessHandler) // Login succeeded
.failureHandler(authenticationFailureHandler) // Login failed
.permitAll()
.and()
.rememberMe().rememberMeParameter("rememberme")
// Prevent iframe from crossing domains
.and()
.headers()
.frameOptions()
.disable()
.and();
// Disable caching
http.headers().cacheControl();
// Add JWT interceptor
// http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); // No access to data returned in JSON format
}
@Bean
public PasswordEncoder passwordEncoder(a) {
return new BCryptPasswordEncoder(12);
}
/** * Authentication interface */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); }}Copy the code
Problems encountered
A, Springsecurity UsernameNotFoundException anomaly can not be normal in the capture
See this article for detailed explanations (very detailed, including solutions)
In short, I throw UsernameNotFoundException but in the end will be converted to BadCredentialsException anomaly. I won’t go into more details here, the above article is very detailed.
Please refer to the article for solutions. What I use is opportunistic method, that is, direct selling BadCredentialsException rather than UsernameNotFoundException anomaly. After all, the final message is a vague “username or password error,” rather than a specific error.
2. Exceptions thrown by filter cannot be uniformly processed
This problem is mainly related to the interception of the verification code, the front end can not get the verification code error message. Instead of using an interceptor to handle the captcha, we can customize a login request to get around this problem.
This problem is also the original writing problem, in fact, the original need to throw the exception, directly output to the page prompt.
I was looking for ways to do this and I found two ways to do this
- 1. The Spring Boot project throws a handler in the custom Filter that the exception cannot catch
- 2. The global unified exception processing fails to intercept the CATCH exception in FILTER
After Syria
This article is a bit messy, the blogger’s writing is really not very good, so it may be a bit hard to understand when describing some of the issues. If you have any questions during the learning process, please add me to QQ (on my code cloud homepage) and let’s discuss and learn together. In the next article we implement user operation logging and exception logging
ingiteeandgithubThe source code is available for updating with this article series