美文网首页Spring Securityspringbootspring boot
spring boot 实例之 用户登录

spring boot 实例之 用户登录

作者: 碧波之心 | 来源:发表于2018-06-06 21:11 被阅读906次

    转载请注明出处spring boot 实例之 用户登录--碧波之心简书

    上两篇完成了用户信息表的增删查,接下来增加用户登录功能。采用spring security来进行权限控制。我们希望用户可以通过用户名+密码、邮箱+密码、手机号+验证码、微信登录三种登录途径。
    先用来完成用户名+密码或手机号+验证码登录。
    前面做的用户信息表不是用来登录的,那些信息只是用户的基本信息。为了在用户列表请求得到的数据中不包含密码、手机号等敏感信息。把登录用的数据分开保存,关联到用户信息。

    建立对象

    创建数据模型 Safety

    package com.biboheart.demo.user.domain;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    import lombok.Data;
    
    @Data
    @Entity
    @Table(name = "bh_user_safety")
    public class Safety {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id; // ID
        private Long uid; // 用户ID
        private String username; // 用户名
        private String mobile; // 手机号
        private String password; // 密码
        private Long createTime; // 创建时间
        private Long updateTime; // 最后修改时间
    }
    
    

    创建repository

    package com.biboheart.demo.user.repository;
    
    import com.biboheart.demo.user.basejpa.CustomRepository;
    import com.biboheart.demo.user.domain.Safety;
    
    public interface SafetyRepository extends CustomRepository<Safety, Long> {
        Safety findByUsernameAndUidNot(String username, Long uid);
        
        Safety findByMobileAndUidNot(String mobile, Long uid);
        
        @Transactional
        void deleteByUid(Long uid);
    }
    

    创建service

    package com.biboheart.demo.user.service;
    
    import com.biboheart.brick.exception.BhException;
    import com.biboheart.demo.user.domain.Safety;
    
    public interface SafetyService {
        public Safety save(Safety safety) throws BhException;
        
        public void delete(Long id, Long uid);
        
        public Safety load(Long uid, String username, String mobile);
    }
    
    package com.biboheart.demo.user.service.impl;
    
    import org.apache.commons.codec.digest.DigestUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import com.biboheart.brick.exception.BhException;
    import com.biboheart.brick.utils.CheckUtils;
    import com.biboheart.brick.utils.TimeUtils;
    import com.biboheart.demo.user.domain.Safety;
    import com.biboheart.demo.user.repository.SafetyRepository;
    import com.biboheart.demo.user.service.SafetyService;
    
    @Service
    public class SafetyServiceImpl implements SafetyService {
        @Autowired
        private SafetyRepository safetyRepository;
    
        @Override
        public Safety save(Safety safety) throws BhException {
            if (null == safety.getId()) {
                safety.setId(0L);
            }
            if (CheckUtils.isEmpty(safety.getUid())) {
                throw new BhException("必须关联到用户");
            }
            if (CheckUtils.isEmpty(safety.getUsername())) {
                if (!CheckUtils.isEmpty(safety.getMobile())) {
                    safety.setUsername(safety.getMobile());
                }
            }
            if (CheckUtils.isEmpty(safety.getUsername())) {
                throw new BhException("用户名不能为空");
            }
            Safety source = safetyRepository.findByUid(safety.getUid());
            if (null != source) {
                safety.setId(source.getId());
            }
            source = safetyRepository.findByUsername(safety.getUsername());
            if (null != source) {
                if (!safety.getUid().equals(source.getUid())) {
                    throw new BhException("用户名已经被占用");
                }
                if (!source.getId().equals(safety.getId())) {
                    if (CheckUtils.isEmpty(safety.getId())) {
                        safety.setId(source.getId());
                    } else {
                        safetyRepository.deleteById(source.getId());
                    }
                }
            }
            source = safetyRepository.findByMobile(safety.getMobile());
            if (null != source) {
                if (!safety.getUid().equals(source.getUid())) {
                    throw new BhException("用户名已经被占用");
                }
                if (!source.getId().equals(safety.getId())) {
                    if (CheckUtils.isEmpty(safety.getId())) {
                        safety.setId(source.getId());
                    } else {
                        safetyRepository.deleteById(source.getId());
                    }
                }
            }
            if (!CheckUtils.isEmpty(safety.getPassword()) && safety.getPassword().length() != 32) {
                safety.setPassword(DigestUtils.md5Hex(safety.getPassword()));
            }
            Long now = TimeUtils.getCurrentTimeInMillis();
            if (CheckUtils.isEmpty(safety.getCreateTime())) {
                safety.setCreateTime(now);
            }
            safety.setUpdateTime(now);
            safety = safetyRepository.save(safety);
            return safety;
        }
    
        @Override
        public void delete(Long id, Long uid) {
            if (!CheckUtils.isEmpty(uid)) {
                safetyRepository.deleteByUid(uid);
            }
            if (!CheckUtils.isEmpty(id)) {
                safetyRepository.deleteById(id);
            }
        }
        
        @Override
        public Safety load(Long uid, String username, String mobile) {
            Safety safety = null;
            if (!CheckUtils.isEmpty(uid)) {
                safety = safetyRepository.findByUid(uid);
            }
            if (null == safety && !CheckUtils.isEmpty(username)) {
                safety = safetyRepository.findByUsername(username);
            }
            if (null == safety && !CheckUtils.isEmpty(mobile)) {
                safety = safetyRepository.findByMobile(mobile);
            }
            return safety;
        }
    
    }
    

    创建控制器

    这里我们先做一个保存的API,如果不保存一个密码的话,登录的功能不方便测试。先简单的实现用户登录的功能,接下去再优化,修改。把能考虑到的不安全因素解决。

    package com.biboheart.demo.user.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.biboheart.brick.exception.BhException;
    import com.biboheart.brick.model.BhResponseResult;
    import com.biboheart.brick.utils.CheckUtils;
    import com.biboheart.demo.user.domain.Safety;
    import com.biboheart.demo.user.domain.User;
    import com.biboheart.demo.user.service.SafetyService;
    import com.biboheart.demo.user.service.UserService;
    
    @RestController
    public class SafetyController {
        @Autowired
        private UserService userService;
        @Autowired
        private SafetyService safetyService;
        
        @RequestMapping(value = "/userapi/safety/save", method = {RequestMethod.POST})
        public BhResponseResult<?> save(Safety safety) throws BhException {
            User user = userService.load(safety.getUid());
            if (null == user) {
                // 如果不是对某个用户设置登录参数则创建一个新用户,用户注册时
                user = new User();
                String name = safety.getUsername();
                if (CheckUtils.isEmpty(name)) {
                    name = safety.getMobile();
                }
                user.setName(name);
                user = userService.save(user);
            }
            safety.setUid(user.getId());
            safety = safetyService.save(safety);
            return new BhResponseResult<>(0, "success", null != safety);
        }
    
    }
    

    创建一个用户

    创建用户
    用户列表

    创建一个用户名为biboheart,手机号为15000000000,密码为test的用户。用户前面的列表接口能查到最新创建的用户。

    开始登录功能

    引入spring security组件,开始开发用户登录功能。

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
    

    创建包:com.biboheart.demo.user.security,用户登录功能都在这个包中完成。
    创建security配置文件

    package com.biboheart.demo.user.security;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    
    import com.biboheart.demo.user.security.filter.BhAuthenticationFilter;
    import com.biboheart.demo.user.security.provider.MobileCodeAuthenticationProvider;
    import com.biboheart.demo.user.security.provider.UsernamePasswordAuthenticationProvider;
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
        @Autowired
        private UsernamePasswordAuthenticationProvider usernamePasswordAuthenticationProvider;
        @Autowired
        private MobileCodeAuthenticationProvider mobileCodeAuthenticationProvider;
        
        @Autowired
        @Qualifier("authenticationManagerBean")
        private AuthenticationManager authenticationManager;
        
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth
                .authenticationProvider(mobileCodeAuthenticationProvider)
                .authenticationProvider(usernamePasswordAuthenticationProvider);
        }
        
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // @formatter:off
            http
                .csrf().disable()
                .addFilterAt(bhAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .authorizeRequests()
                    .antMatchers("/", "/home", "/loginIn", "/oauth/authorize", "/oauth/token").permitAll()
                    .anyRequest().authenticated()
                    .and()
                .formLogin()
                    .loginPage("/login")
                    .permitAll()
                    .and()
                .logout()
                    .permitAll();
            // @formatter:on
        }
        
        @Bean
        public BhAuthenticationFilter bhAuthenticationFilter() {
            BhAuthenticationFilter filter = new BhAuthenticationFilter();
            filter.setAuthenticationManager(authenticationManager);
            return filter;
        }
        
        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    }
    

    因为我们有两种登录方式,所以我们建立usernamePasswordAuthenticationProvider和mobileCodeAuthenticationProvider两个provider来处理登录请求。
    UsernamePasswordAuthenticationToken是spring security内置的token对象。我们就不再定义了,需要定义一个MobileCodeAuthenticationToken在包com.biboheart.demo.user.security.tokens中

    package com.biboheart.demo.user.security.tokens;
    
    import java.util.Collection;
    
    import org.springframework.security.authentication.AbstractAuthenticationToken;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.SpringSecurityCoreVersion;
    
    public class MobileCodeAuthenticationToken extends AbstractAuthenticationToken {
        
        private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
        
        private final Object principal;
        private String credentials;
    
        public MobileCodeAuthenticationToken(Object principal, String credentials) {
            super(null);
            this.principal = principal;
            this.credentials = credentials;
            setAuthenticated(false);
        }
        
        public MobileCodeAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
            super(authorities);
            this.principal = principal;
            this.credentials = null;
            super.setAuthenticated(true); // must use super, as we override
        }
    
        // ~ Methods
        // ========================================================================================================
    
        public String getCredentials() {
            return this.credentials;
        }
    
        public Object getPrincipal() {
            return this.principal;
        }
    
        public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
            if (isAuthenticated) {
                throw new IllegalArgumentException(
                        "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
            }
    
            super.setAuthenticated(false);
        }
    
        @Override
        public void eraseCredentials() {
            super.eraseCredentials();
            credentials = null;
        }
    
    }
    

    创建过滤器

    创建一个过滤器,替换掉原来的UsernamePasswordAuthenticationFilter过滤器。定义为BhAuthenticationFilter 继承至 AbstractAuthenticationProcessingFilter。

    package com.biboheart.demo.user.security.filter;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.security.authentication.AbstractAuthenticationToken;
    import org.springframework.security.authentication.AuthenticationServiceException;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
    import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
    import org.springframework.util.Assert;
    
    import com.biboheart.demo.user.security.tokens.MobileCodeAuthenticationToken;
    
    public class BhAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
        // ~ Static fields/initializers
        // =====================================================================================
    
        public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
        public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
        public static final String SPRING_SECURITY_FORM_AUTYPE_KEY = "autype";
    
        private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
        private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
        private String autypeParameter = SPRING_SECURITY_FORM_AUTYPE_KEY;
        private boolean postOnly = true;
    
        // ~ Constructors
        // ===================================================================================================
    
        public BhAuthenticationFilter() {
            super(new AntPathRequestMatcher("/login", "POST"));
        }
    
        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
                throws AuthenticationException, IOException, ServletException {
            if (postOnly && !request.getMethod().equals("POST")) {
                throw new AuthenticationServiceException(
                        "Authentication method not supported: " + request.getMethod());
            }
            
            String username = obtainUsername(request);
            String password = obtainPassword(request);
            String autype = obtainAutype(request);
            System.out.println(this.getClass().getName() + "----autype:" + autype);
    
            if (username == null) {
                username = "";
            }
    
            if (password == null) {
                password = "";
            }
            
            if (autype == null) {
                autype = "";
            }
    
            username = username.trim();
            
            AbstractAuthenticationToken authRequest = null;
            switch(autype) {
            case "mobileCode":
                authRequest = new MobileCodeAuthenticationToken(username, password);
                break;
            default:
                authRequest = new UsernamePasswordAuthenticationToken(username, password);
                break;
            }
    
            /*UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
                    username, password);*/
    
            // Allow subclasses to set the "details" property
            setDetails(request, authRequest);
    
            return this.getAuthenticationManager().authenticate(authRequest);
        }
        
        protected String obtainPassword(HttpServletRequest request) {
            return request.getParameter(passwordParameter);
        }
        
        protected String obtainUsername(HttpServletRequest request) {
            return request.getParameter(usernameParameter);
        }
        
        protected String obtainAutype(HttpServletRequest request) {
            return request.getParameter(autypeParameter);
        }
        
        protected void setDetails(HttpServletRequest request,
                AbstractAuthenticationToken authRequest) {
            authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
        }
        
        public void setAutypeParameter(String autypeParameter) {
            Assert.hasText(autypeParameter, "Autype parameter must not be empty or null");
            this.autypeParameter = autypeParameter;
        }
        
        public void setUsernameParameter(String usernameParameter) {
            Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
            this.usernameParameter = usernameParameter;
        }
        
        public void setPasswordParameter(String passwordParameter) {
            Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
            this.passwordParameter = passwordParameter;
        }
        
        public void setPostOnly(boolean postOnly) {
            this.postOnly = postOnly;
        }
    
        public final String getUsernameParameter() {
            return usernameParameter;
        }
    
        public final String getPasswordParameter() {
            return passwordParameter;
        }
    
    }
    

    对于登录请求,我们接收三个参数。分别是:username,password,autype。autype参数用于告知登录类型:默认为用户名密码方式,mobileCode为手机号验证码方式。如果是mobileCode方式,那么username对应的是手机号,password对应的是验证码。
    通过SecurityConfiguration中的.addFilterAt(bhAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)插入过滤器。

    实现用户认证

    用户名密码认证的实现

    package com.biboheart.demo.user.security.provider;
    
    import java.util.HashSet;
    import java.util.Set;
    
    import org.apache.commons.codec.digest.DigestUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.AuthenticationProvider;
    import org.springframework.security.authentication.BadCredentialsException;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.stereotype.Component;
    
    import com.biboheart.brick.utils.CheckUtils;
    import com.biboheart.demo.user.domain.Safety;
    import com.biboheart.demo.user.domain.User;
    import com.biboheart.demo.user.service.SafetyService;
    import com.biboheart.demo.user.service.UserService;
    
    @Component
    public class UsernamePasswordAuthenticationProvider implements AuthenticationProvider {
        @Autowired
        private SafetyService safetyService;
        @Autowired
        private UserService userService;
    
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();
            String password = (String) authentication.getCredentials();
            if (CheckUtils.isEmpty(password)) {
                throw new BadCredentialsException("密码不能为空");
            }
            Safety safety = safetyService.load(null, username, null);
            if (null == safety) {
                throw new BadCredentialsException("用户不存在");
            }
            User user = userService.load(safety.getUid());
            if (null == user) {
                throw new BadCredentialsException("用户不存在");
            }
            if (password.length() != 32) {
                password = DigestUtils.md5Hex(password);
            }
            if (!password.equals(safety.getPassword())) {
                throw new BadCredentialsException("用户名或密码不正确");
            }
            UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(username, password, listUserGrantedAuthorities(user.getId()));
            result.setDetails(authentication.getDetails());
            return result;
        }
    
        @Override
        public boolean supports(Class<?> authentication) {
            System.out.println(this.getClass().getName() + "---supports");
            return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
        }
    
        private Set<GrantedAuthority> listUserGrantedAuthorities(Long uid) {
            Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
            if (CheckUtils.isEmpty(uid)) {
                return authorities;
            }
            authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
            return authorities;
        }
    
    }
    

    手机号验证码认证的实现

    package com.biboheart.demo.user.security.provider;
    
    import java.util.HashSet;
    import java.util.Set;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.authentication.AuthenticationProvider;
    import org.springframework.security.authentication.BadCredentialsException;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.AuthenticationException;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.stereotype.Component;
    
    import com.biboheart.brick.utils.CheckUtils;
    import com.biboheart.demo.user.domain.Safety;
    import com.biboheart.demo.user.domain.User;
    import com.biboheart.demo.user.security.tokens.MobileCodeAuthenticationToken;
    import com.biboheart.demo.user.service.SafetyService;
    import com.biboheart.demo.user.service.UserService;
    
    @Component
    public class MobileCodeAuthenticationProvider implements AuthenticationProvider {
        @Autowired
        private SafetyService safetyService;
        @Autowired
        private UserService userService;
    
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            String mobile = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();
            String code = (String) authentication.getCredentials();
            if (CheckUtils.isEmpty(code)) {
                throw new BadCredentialsException("验证码不能为空");
            }
            Safety safety = safetyService.load(null, null, mobile);
            if (null == safety) {
                throw new BadCredentialsException("用户不存在");
            }
            User user = userService.load(safety.getUid());
            if (null == user) {
                throw new BadCredentialsException("用户不存在");
            }
            // 手机号验证码业务还没有开发,先用4个0验证
            if (!code.equals("0000")) {
                throw new BadCredentialsException("验证码不正确");
            }
            UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(safety.getUsername(), code, listUserGrantedAuthorities(user.getId()));
            result.setDetails(authentication.getDetails());
            return result;
        }
    
        @Override
        public boolean supports(Class<?> authentication) {
            System.out.println(this.getClass().getName() + "---supports");
            return (MobileCodeAuthenticationToken.class.isAssignableFrom(authentication));
        }
    
        private Set<GrantedAuthority> listUserGrantedAuthorities(Long uid) {
            Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
            if (CheckUtils.isEmpty(uid)) {
                return authorities;
            }
            authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
            return authorities;
        }
    
    }
    

    更多的认证方式照着扩展就可以了。

    用户登录界面

    用户登录需要界面,未登录时要跳转到登录界面,登录成功后要跳转到首页。
    页面跳转控制器

    package com.biboheart.demo.user.security.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    @Controller
    public class SecurityController {
    
        @RequestMapping(value = "/login", method = RequestMethod.GET)
        public String loginPage() {
            return "login";
        }
    }
    

    首页控制器

    package com.biboheart.demo.user.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    @Controller
    public class HelloController {
        
        @RequestMapping(value = { "/", "/home" }, method = RequestMethod.GET)
        public String homePage() {
            return "index";
        }
        
        @RequestMapping(value = "/hello", method = RequestMethod.GET)
        public String hello() {
            return "hello";
        }
    
    }
    

    index.html

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8"></meta>
        <title>Spring Security入门</title>
    </head>
    <body>
        <h1>欢迎使用Spring Security!</h1>
        <p>
            点击 <a href="/hello">这里</a> 打个招呼吧
        </p>
    </body>
    </html>
    

    hello.html

    <!DOCTYPE html>
    <html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8"></meta>
        <title>Hello World!</title>
    </head>
    <body>
        <h1>Hello world!</h1>
        <a href="/logout">注销</a>
        <form th:action="@{/logout}" method="post">
            <input type="submit" value="Sign Out"/>
        </form>
        <h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
    </body>
    </html>
    

    login.html

    <!DOCTYPE html>
    <html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8"></meta>
        <title>登录</title>
    </head>
    <body>
        <div th:if="${param.containsKey('error')}">
            <p class="error">登录不成功,可能是用户名/密码错了</p>
        </div>
        <div th:if="${param.containsKey('logout')}">
            <h4>成功 </h4>
            <p>您已经成功退出</p>
        </div>
        <form method="post" role="form">
            <div class="form-group">
                用户名密码认证 <input name="autype" type="radio" value="usernamePassword" checked="checked"/>
                手机号验证码 <input name="autype" type="radio" value="mobileCode"/>
            </div>
            <div class="form-group">
                <label for="username">用户名:</label>
                <input type='text' name='username'/>
            </div>
            <div class="form-group">
                <label for="password">密码:</label>
                <input type='password' name='password'/>
            </div>
            <!-- <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> -->
            <button class="btn btn-primary" type="submit">登录</button>
        </form>
        With Github: <a href="/login/github">click here</a>
    </body>
    </html>
    

    在pom.xml中引入组件

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
    
    首页

    首页是允许访问的,点击“这里”的链接。就进入登录页面。


    登录界面

    选择手机号验证码登录:


    手机号登录
    实际上这里用户和密码输入的是手机号和验证码(0000),前端可以控制,根据不同的选择改下提示文字。
    点击登录后进入hello页面
    hello页面

    可以点击注销,再试试用户名密码登录。

    总结

    1. 创建用户认证的信息对象;
    2. 引入spring security;
    3. spring security配置文件;
    4. 自定义token;
    5. 自定义provider;
    6. 登录页面
      当前目录结构:


      目录结构

    相关文章

      网友评论

        本文标题:spring boot 实例之 用户登录

        本文链接:https://www.haomeiwen.com/subject/ovcisftx.html