spring-security-oauth2 自定义登录页面

JAVA herman 138浏览
公告:“业余草”微信公众号提供免费CSDN下载服务,关注业余草微信公众号,添加作者微信:xmtxtt,发送下载链接帮助你免费下载!
本博客日IP超过1300,PV 1800 左右,急需赞助商。
打开支付宝首页搜“567452957”领红包,间接赞助博主,谢谢!

一个网站的登录页面就相当于一个人的脸,脸往往给人留下第一印象。印象好,就会带来好体验。好体验就可能有更高的活跃度,所以像我前面《SpringBoot + spring-security-oauth2 实现仿微信,QQ,微博等授权认证》中的漂亮的登录页面该如何定制呢?本文,我们一起来实践一把吧。

严格来说,这个登录页面的定制化,并不算 spring-security-oauth2 中的功能,而是靠 Spring Security 来实现的。在 OAuth2 中我们可以针对不同的应用有不同的登录页面,这个登录页面的代码在 Server 端,认证我们可以放在客户端 Client 中。

实现的原理很简单,就是当我们要访问未授权的页面时,进行拦截,通过 @EnableOAuth2Sso 注解,让它通过 OAuth2 到 AuthenticationProvider 中去认证。

首先,我们要实现 WebSecurityConfigurerAdapter,配置哪些资源需要拦截,哪些不需要认证。

@Configuration  
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)  
@EnableWebSecurity  
static class SecurityConfig extends WebSecurityConfigurerAdapter {  
    @Override  
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {  
        auth.authenticationProvider(authenticationProvider);  
    }
    @Override  
    protected void configure(HttpSecurity http) throws Exception {  
      http.csrf().disable();  
      http.antMatcher("/oauth/**")  
        .authorizeRequests()  
          .antMatchers("/oauth/index").permitAll()  
          .antMatchers("/oauth/token").permitAll()  
          .antMatchers("/oauth/check_token").permitAll()  
          .antMatchers("/oauth/confirm_access").permitAll()  
          .antMatchers("/oauth/error").permitAll()  
          .antMatchers("/oauth/approvale/confirm").permitAll()  
          .antMatchers("/oauth/approvale/error").permitAll()  
          .anyRequest().authenticated()  
        .and()  
          .formLogin()  
          .loginPage("/oauth/index")
          .loginProcessingUrl("/oauth/login");  
    }  
    @Autowired  
    private CustomAuthenticationProvider authenticationProvider;  
}

登录认证部分,我们通过实现 AuthenticationProvider 接口,对接数据库来实现。

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
  @Autowired
  private AccountService accountService;  
  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    String name = authentication.getName();
    String password = authentication.getCredentials().toString();
    Account account = accountService.authUser(name, password);
    if (account == null) {
      throw new AuthenticationCredentialsNotFoundException("Account is not found.");  
    }
    List<GrantedAuthority> grantedAuths = AuthorityUtils.createAuthorityList(account.getRoleString());
    return new UsernamePasswordAuthenticationToken(name, password, grantedAuths);  
  }  
  @Override
  public boolean supports(Class<?> authentication) {
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
  }
}

业务逻辑层 AccountService 的代码如下:

@Service  
public class AccountService {  
  @Autowired  
  private AccountRepository accountRepository;  
  public Account authUser(String userName, String password) {  
    Account u = accountRepository.findByUserName(userName);  
    if (u == null) {  
      return null;  
    }  
    if (!u.getPassword().equals(password)) {  
      return null;  
    }  
    return u;
  }  
}  

AccountRepository 代码如下:

public interface AccountRepository {  
  @Select("select id, user_name as userName, email, password, role_string as roleString from account where user_name=#{user_name}")  
  Account findByUserName(String userName);  
}  

实体类:

@SuppressWarnings("serial")  
public class Account implements Serializable {  
  private Integer id;  
  private String userName;  
  private String email;  
  private String password;  
  private String roleString;  
  // ...setter/getter  
} 

SQL:

CREATE TABLE account  
(  
  id serial NOT NULL,  
  user_name character varying(50),  
  email character varying(255),  
  password character varying(512),  
  role_string character varying(50),  
  CONSTRAINT account_pkey PRIMARY KEY (id)  
);  
INSERT INTO account(user_name, email, password, role_string)  
    VALUES ('user', 'user@sample.com', '123', 'ROLE_USER');  

扫描包:

@Configuration  
@MapperScan("com.rensanning")  
@EnableTransactionManagement(proxyTargetClass = true)  
static class RepositoryConfig {  
}  

登录页面代码:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Insert title here</title>
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  <script src="https://cdn.bootcss.com/vue/2.5.17/vue.min.js"></script>
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
</head>
<body>
<div class="login-box" id="app" >
   <el-form action="/auth/login" method="post" label-position="left" label-width="0px" class="demo-ruleForm login-container">
    <h2 class="title" >统一认证登录平台</h2>
    <el-form-item>
      <el-input type="text"  name="username" v-model="username" auto-complete="off" placeholder="账号"></el-input>
    </el-form-item>
    <el-form-item>
      <el-input type="password" name="password" v-model="password" auto-complete="off" placeholder="密码"></el-input>
    </el-form-item>
    <el-form-item style="width:100%; text-align:center;">
      <el-button type="primary" style="width:47%;" @click.native.prevent="reset">重 置</el-button>
      <el-button type="primary" style="width:47%;" native-type="submit" :loading="loading">登 录</el-button>
    </el-form-item>
  <el-form>
</div> 
</body>
<script type="text/javascript">
  new Vue({
    el : '#app',
    data : {
      loading: false,
          username: 'admin',
          password: '123'
    },
    methods : {
      reset: function() {
        this.username = 'admin'
        this.password = '123'
      }
    }
  })
</script>
<style lang="scss" scoped>
  .login-container {
    -webkit-border-radius: 5px;
    border-radius: 5px;
    -moz-border-radius: 5px;
    background-clip: padding-box;
    margin: 100px auto;
    width: 320px;
    padding: 35px 35px 15px 35px;
    background: #fff;
    border: 1px solid #eaeaea;
    box-shadow: 0 0 25px #cac6c6;
  }
  .title {
    margin: 0px auto 20px auto;
    text-align: center;
    color: #505458;
  }
</style>
</html>

注意,pom.xml 中,需要引入 spring-boot-starter-thymeleaf,最终运行效果:

OAuth2 定制好看的登录页面

参考资料

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847(已满),QQ3群:187424846(已满)。QQ群进群密码:xttblog,想加微信群的朋友,可以微信搜索:xmtxtt,备注:“xttblog”,添加助理微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » spring-security-oauth2 自定义登录页面