Spring Security(三)
程序员文章站
2022-04-18 15:27:19
Spring Security(三) 个性化用户认证流程 自定义登录页面 在配置类中指定登录页面和接收登录的 url 在项目中新建登录页面 启动项目时再访问 Security 就会跳转到你自已定义的登陆页面让你登录。 深入定义(判断是PC端还是移动端,PC端跳转页面,移动端响应 json) 创建一个 ......
spring security(三)
个性化用户认证流程
自定义登录页面
在配置类中指定登录页面和接收登录的 url
@configuration public class browsersecurityconfig extends websecurityconfigureradapter { @bean public passwordencoder passwordencoder() { return new mypasswordencoder(); } @override protected void configure(httpsecurity http) throws exception { // 启用表单登陆 http.formlogin() // 指定登录页面 .loginpage("/imooc-signin.html") // 登录页面表单提交的 action .loginprocessingurl("/authentication/form") .and() // 对请求做授权 .authorizerequests() // 访问指定url时不需要身份认证(放行) .antmatchers("/imooc-signin.html").permitall() // 任何请求 .anyrequest() // 都需要身份认证 .authenticated() .and() .csrf().disable(); } }
- 在项目中新建登录页面
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>登录</title> </head> <body> <h2>标准登录页面</h2> <h3>表单登录</h3> <form action="/authentication/form" method="post"> <table> <tr> <td>用户名:</td> <td><label> <input type="text" name="username" /> </label></td> </tr> <tr> <td>密码:</td> <td><label> <input type="password" name="password" /> </label> </td> </tr> <tr> <td colspan="2"> <button type="submit">登录</button> </td> </tr> </table> </form> </body> </html>
启动项目时再访问 security 就会跳转到你自已定义的登陆页面让你登录。
- 深入定义(判断是pc端还是移动端,pc端跳转页面,移动端响应 json)
创建一个控制器,用来处理操作
@restcontroller public class browsersecuritycontroller { private static final logger log = loggerfactory.getlogger(browsersecuritycontroller.class); private requestcache requestcache = new httpsessionrequestcache(); private redirectstrategy redirectstrategy = new defaultredirectstrategy(); /** * 当需要身份验证时跳转到这里处理 */ @requestmapping("/authentication/require") @responsestatus(code = httpstatus.unauthorized) public map<string, string> requireauthentication(final httpservletrequest request, final httpservletresponse response) throws ioexception { savedrequest savedrequest = requestcache.getrequest(request, response); if (null != savedrequest) { string target = savedrequest.getredirecturl(); log.info("引发跳转的请求是 ={}", target); if (stringutils.endswithignorecase(target, ".html")) { redirectstrategy.sendredirect(request, response, "/imooc-signin.html"); } } map<string, string> map = new hashmap<>(); map.put("status", "401"); map.put("msg", "error"); map.put("content","访问的服务需要身份认证,请引导用户到登录页!" ); return map; } }
自定义登录成功处理
要做自定义登录成功处理需要实现一下 security 的 authenticationsuccesshandler 接口
/** * 自定义登录成功处理 */ @configuration public class imoocauthenticationsuccesshandler implements authenticationsuccesshandler { private static final logger log = loggerfactory.getlogger(imoocauthenticationsuccesshandler.class); private final objectmapper objectmapper; @autowired public imoocauthenticationsuccesshandler(objectmapper objectmapper) { this.objectmapper = objectmapper; } // 参数 authentication 是security的核心接口之一,封装了用户登录认证信息 // userdetails 接口就包装到了此接口中 @override public void onauthenticationsuccess(httpservletrequest request, httpservletresponse response, authentication authentication) throws ioexception, servletexception { log.info("登录成功"); // 响应 json 信息 response.setcontenttype("application/json;charset=utf-8"); printwriter out = response.getwriter(); out.write(objectmapper.writevalueasstring(authentication)); out.flush(); out.close(); } }
- 启动项目,访问跳转登录页面后,输入正确用户名,密码后响应信息如下:
{ "authorities": [ { "authority": "admin" } ], // 包含了认证请求的信息 "details": { "remoteaddress": "127.0.0.1", "sessionid": "1126c43793fd600ca6dc74169a38f64e" }, // 这里代表当前用户是否经过了身份认证,boolean表示 "authenticated": true, // 这里是 我们自定义userdetailsservice接口实现类 返回的数据 "principal": { "password": null, "username": "user", // 用户权限 "authorities": [ { "authority": "admin" } ], "accountnonexpired": true, "accountnonlocked": true, "credentialsnonexpired": true, "enabled": true }, // 这里一般代表用户输入的密码,security 做了处理,前台不会响应 "credentials": null, // 用户名 "name": "user" }
自定义登录错误处理
要做自定义登录成功处理需要实现一下 security 的 authenticationfailurehandler 接口
/** * 自定义登录失败处理 */ @configuration public class imoocauthenticationfailurehandler implements authenticationfailurehandler { // 参数 authenticationexception 是 security 的一个抽象异常类 @override public void onauthenticationfailure(httpservletrequest request, httpservletresponse response, authenticationexception exception) throws ioexception, servletexception { } }
- 启动项目,访问跳转登录页面后,输入错误用户名,密码后响应信息如下:
{**省略堆栈信息**"localizedmessage":"坏的凭证","message":"坏的凭证","suppressed":[]}
注意:以上两个自定义登录/失败的处理,一定要在 自定义security配置类中加入,不然不会生效!!!
加入自定义登录成功/失败处理
/** * security 配置 */ @configuration public class browsersecurityconfig extends websecurityconfigureradapter { @autowired private securityproperties securityproperties; @autowired private imoocauthenticationsuccesshandler imoocauthenticationsuccesshandler; @autowired private imoocauthenticationfailurehandler imoocauthenticationfailurehandler; @bean public passwordencoder passwordencoder() { return new mypasswordencoder(); } @override protected void configure(httpsecurity http) throws exception { browserproperties browser = securityproperties.getbrowser(); // 启用表单登陆 http.formlogin() // 指定登录页面 .loginpage("/authentication/require") // 登录页面表单提交的 action .loginprocessingurl("/authentication/form") // 引入自己定义的登录成功处理配置类 .successhandler(imoocauthenticationsuccesshandler) // 引入自己定义的登录失败处理配置类 .failurehandler(imoocauthenticationfailurehandler) .and() // 对请求做授权 .authorizerequests() // 访问指定url时不需要身份认证(放行) .antmatchers("/authentication/require", browser.getloginpage()).permitall() // 任何请求 .anyrequest() // 都需要身份认证 .authenticated() .and() .csrf().disable(); } }
以上实现了自定义成功/失败响应,但是要想pc/移动端通用,需要深化配置一下
- 改造 自定义成功处理
创建一个枚举类,用来区分 重定向,还是响应 json
public enum logintype { redirect, json; }
让此枚举类成为 browserproperties 类的一个属性
public class browserproperties { /** * 指定默认值(如果配置了用配置的页面,没配置用默认的。) */ private string loginpage = "/imooc-signin.html"; /** * 指定登录成功/失败后的响应方式 */ private logintype logintype = logintype.json; // 省略 get/set/tostring 方法 }
改造自定义成功处理类
/** * 自定义登录成功处理 */ @configuration // 让自定义的成功处理类 继承 security 默认的成功处理类 savedrequestawareauthenticationsuccesshandler public class imoocauthenticationsuccesshandler extends savedrequestawareauthenticationsuccesshandler { private static final logger log = loggerfactory.getlogger(imoocauthenticationsuccesshandler.class); private final objectmapper objectmapper; private final securityproperties securityproperties; @autowired public imoocauthenticationsuccesshandler(objectmapper om, securityproperties sp) { this.objectmapper = om; this.securityproperties = sp; } @override public void onauthenticationsuccess(httpservletrequest request, httpservletresponse response, authentication authentication) throws ioexception, servletexception { log.info("登录成功。。。"); // 响应 json 信息 response.setcontenttype("application/json;charset=utf-8"); printwriter out = response.getwriter(); out.write(objectmapper.writevalueasstring(authentication)); out.flush(); out.close(); } }
改造自定义失败处理类
/** * 自定义登录失败处理 */ @configuration // simpleurlauthenticationfailurehandler 为 security 默认的登录失败处理类 public class imoocauthenticationfailurehandler extends simpleurlauthenticationfailurehandler { private static final logger log = loggerfactory.getlogger(imoocauthenticationsuccesshandler.class); private final objectmapper objectmapper; private final securityproperties securityproperties; @autowired public imoocauthenticationfailurehandler(objectmapper om, securityproperties sp) { this.objectmapper = om; this.securityproperties = sp; } @override public void onauthenticationfailure(httpservletrequest request, httpservletresponse response, authenticationexception exception) throws ioexception, servletexception { log.info("登录失败。。。"); // 如果配置了用 json 响应 if (logintype.json.equals(securityproperties.getbrowser().getlogintype())) { // 响应状态码为 500 response.setstatus(httpstatus.internal_server_error.value()); // 响应 json 信息 response.setcontenttype("application/json;charset=utf-8"); printwriter out = response.getwriter(); out.write(objectmapper.writevalueasstring(exception)); out.flush(); out.close(); } else { // 调用父类方法 super.onauthenticationfailure(request, response, exception); } } }
由于 browserproperties 类中的logintype属性默认为 json ,你可以在具体的 properties 文件中,定义一下属性。如:
imooc.security.browser.login-type=redirect这样可以测试一下是否配置成功。
测试图就不贴上了,自已耐心测试一下~ :-)
下一篇: WinForm 双向数据绑定