最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring-Security實(shí)現(xiàn)登錄接口流程

 更新時間:2023年05月29日 16:30:32   作者:韭菜蓋飯  
Security?是?Spring?家族中的一個安全管理框架,SpringSecurity的原理其實(shí)就是一個過濾器鏈,內(nèi)部包含了提供各種功能的過濾器,這篇文章主要介紹了Spring-Security實(shí)現(xiàn)登錄接口,需要的朋友可以參考下

簡介

SecuritySpring 家族中的一個安全管理框架。相比與另外一個安全框架Shiro,它提供了更豐富的功能,社區(qū)資源也比Shiro豐富。

具體介紹和入門看springSecurity入門

原理初探

在實(shí)現(xiàn)之前幺要了解一下登錄校驗(yàn)的流程以及SpringSecurity的原理以及認(rèn)證流程

1、登錄校驗(yàn)流程

2、 SpringSecurity完整流程

SpringSecurity的原理其實(shí)就是一個過濾器鏈,內(nèi)部包含了提供各種功能的過濾器。這里我們可以看看入門案例中的過濾器。

圖中只展示了核心過濾器,其它的非核心過濾器并沒有在圖中展示。

UsernamePasswordAuthenticationFilter:負(fù)責(zé)處理我們在登陸頁面填寫了用戶名密碼后的登陸請求。入門案例的認(rèn)證工作主要有它負(fù)責(zé)。

ExceptionTranslationFilter:處理過濾器鏈中拋出的任何AccessDeniedExceptionAuthenticationException 。

FilterSecurityInterceptor:負(fù)責(zé)權(quán)限校驗(yàn)的過濾器。

我們可以通過Debug查看當(dāng)前系統(tǒng)中SpringSecurity過濾器鏈中有哪些過濾器及它們的順序。

3、認(rèn)證流程

概念速查:

  • Authentication接口: 它的實(shí)現(xiàn)類,表示當(dāng)前訪問系統(tǒng)的用戶,封裝了用戶相關(guān)信息。
  • AuthenticationManager接口:定義了認(rèn)證Authentication的方法
  • UserDetailsService接口:加載用戶特定數(shù)據(jù)的核心接口。里面定義了一個根據(jù)用戶名查詢用戶信息的方法。
  • UserDetails接口:提供核心用戶信息。通過UserDetailsService根據(jù)用戶名獲取處理的用戶信息要封裝成UserDetails對象返回。然后將這些信息封裝到Authentication對象中。

實(shí)現(xiàn)思路

登錄

? ①自定義登錄接口

? 調(diào)用ProviderManager的方法進(jìn)行認(rèn)證 如果認(rèn)證通過生成jwt

? 把用戶信息存入redis

? ②自定義UserDetailsService

? 在這個實(shí)現(xiàn)類中去查詢數(shù)據(jù)庫

校驗(yàn):

? ①定義Jwt認(rèn)證過濾器

? 獲取token

? 解析token獲取其中的userid

? 從redis中獲取用戶信息

? 存入SecurityContextHolder

這里我們主要是實(shí)現(xiàn)登錄接口的功能
核心思想就是就是將認(rèn)證流程 中的UserDetailsService 重寫其loadUserByUsername的方法,使其從數(shù)據(jù)庫中查詢數(shù)據(jù),然后用自己的類(我這里是UserLogin)實(shí)現(xiàn)UserDetails,在loadUserByUsername中返回UserLogin

登錄接口實(shí)現(xiàn)

準(zhǔn)備工作

添加依賴,添加工具類,創(chuàng)建數(shù)據(jù)庫,編寫配置文件
1、添加依賴

 <!--redis依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--fastjson依賴-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.33</version>
        </dependency>
        <!--jwt依賴-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

2、添加Redis相關(guān)配置

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson.parser.ParserConfig;
import org.springframework.util.Assert;
import java.nio.charset.Charset;
/**
 * Redis使用FastJson序列化
 * 
 * @author sg
 */
public class FastJsonRedisSerializer<T> implements RedisSerializer<T>
{
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private Class<T> clazz;
    static
    {
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
    }
    public FastJsonRedisSerializer(Class<T> clazz)
    {
        super();
        this.clazz = clazz;
    }
    @Override
    public byte[] serialize(T t) throws SerializationException
    {
        if (t == null)
        {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }
    @Override
    public T deserialize(byte[] bytes) throws SerializationException
    {
        if (bytes == null || bytes.length <= 0)
        {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
        return JSON.parseObject(str, clazz);
    }
    protected JavaType getJavaType(Class<?> clazz)
    {
        return TypeFactory.defaultInstance().constructType(clazz);
    }
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
    @Bean
    @SuppressWarnings(value = { "unchecked", "rawtypes" })
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
    {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);
        // 使用StringRedisSerializer來序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);
        // Hash的key也采用StringRedisSerializer的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);
        template.afterPropertiesSet();
        return template;
    }
}

封裝返回的數(shù)據(jù)

import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseResult<T> {
    /**
     * 狀態(tài)碼
     */
    private Integer code;
    /**
     * 提示信息,如果有錯誤時,前端可以獲取該字段進(jìn)行提示
     */
    private String msg;
    /**
     * 查詢到的結(jié)果數(shù)據(jù),
     */
    private T data;
    public ResponseResult(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public ResponseResult(Integer code, T data) {
        this.code = code;
        this.data = data;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }
    public ResponseResult(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
}

JWT工具類

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
/**
 * JWT工具類
 */
public class JwtUtil {
    //有效期為
    public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000  一個小時
    //設(shè)置秘鑰明文
    public static final String JWT_KEY = "sangeng";
    public static String getUUID(){
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        return token;
    }
    /**
     * 生成jtw
     * @param subject token中要存放的數(shù)據(jù)(json格式)
     * @return
     */
    public static String createJWT(String subject) {
        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 設(shè)置過期時間
        return builder.compact();
    }
    /**
     * 生成jtw
     * @param subject token中要存放的數(shù)據(jù)(json格式)
     * @param ttlMillis token超時時間
     * @return
     */
    public static String createJWT(String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 設(shè)置過期時間
        return builder.compact();
    }
    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        SecretKey secretKey = generalKey();
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if(ttlMillis==null){
            ttlMillis=JwtUtil.JWT_TTL;
        }
        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis);
        return Jwts.builder()
                .setId(uuid)              //唯一的ID
                .setSubject(subject)   // 主題  可以是JSON數(shù)據(jù)
                .setIssuer("sg")     // 簽發(fā)者
                .setIssuedAt(now)      // 簽發(fā)時間
                .signWith(signatureAlgorithm, secretKey) //使用HS256對稱加密算法簽名, 第二個參數(shù)為秘鑰
                .setExpiration(expDate);
    }
    /**
     * 創(chuàng)建token
     * @param id
     * @param subject
     * @param ttlMillis
     * @return
     */
    public static String createJWT(String id, String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 設(shè)置過期時間
        return builder.compact();
    }
    public static void main(String[] args) throws Exception {
        String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjYWM2ZDVhZi1mNjVlLTQ0MDAtYjcxMi0zYWEwOGIyOTIwYjQiLCJzdWIiOiJzZyIsImlzcyI6InNnIiwiaWF0IjoxNjM4MTA2NzEyLCJleHAiOjE2MzgxMTAzMTJ9.JVsSbkP94wuczb4QryQbAke3ysBDIL5ou8fWsbt_ebg";
        Claims claims = parseJWT(token);
        System.out.println(claims);
    }
    /**
     * 生成加密后的秘鑰 secretKey
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }
    /**
     * 解析
     *
     * @param jwt
     * @return
     * @throws Exception
     */
    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }
}

Redis工具類

import java.util.*;
import java.util.concurrent.TimeUnit;
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisCache
{
    @Autowired
    public RedisTemplate redisTemplate;
    /**
     * 緩存基本的對象,Integer、String、實(shí)體類等
     *
     * @param key 緩存的鍵值
     * @param value 緩存的值
     */
    public <T> void setCacheObject(final String key, final T value)
    {
        redisTemplate.opsForValue().set(key, value);
    }
    /**
     * 緩存基本的對象,Integer、String、實(shí)體類等
     *
     * @param key 緩存的鍵值
     * @param value 緩存的值
     * @param timeout 時間
     * @param timeUnit 時間顆粒度
     */
    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
    {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }
    /**
     * 設(shè)置有效時間
     *
     * @param key Redis鍵
     * @param timeout 超時時間
     * @return true=設(shè)置成功;false=設(shè)置失敗
     */
    public boolean expire(final String key, final long timeout)
    {
        return expire(key, timeout, TimeUnit.SECONDS);
    }
    /**
     * 設(shè)置有效時間
     *
     * @param key Redis鍵
     * @param timeout 超時時間
     * @param unit 時間單位
     * @return true=設(shè)置成功;false=設(shè)置失敗
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit)
    {
        return redisTemplate.expire(key, timeout, unit);
    }
    /**
     * 獲得緩存的基本對象。
     *
     * @param key 緩存鍵值
     * @return 緩存鍵值對應(yīng)的數(shù)據(jù)
     */
    public <T> T getCacheObject(final String key)
    {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }
    /**
     * 刪除單個對象
     *
     * @param key
     */
    public boolean deleteObject(final String key)
    {
        return redisTemplate.delete(key);
    }
    /**
     * 刪除集合對象
     *
     * @param collection 多個對象
     * @return
     */
    public long deleteObject(final Collection collection)
    {
        return redisTemplate.delete(collection);
    }
    /**
     * 緩存List數(shù)據(jù)
     *
     * @param key 緩存的鍵值
     * @param dataList 待緩存的List數(shù)據(jù)
     * @return 緩存的對象
     */
    public <T> long setCacheList(final String key, final List<T> dataList)
    {
        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
        return count == null ? 0 : count;
    }
    /**
     * 獲得緩存的list對象
     *
     * @param key 緩存的鍵值
     * @return 緩存鍵值對應(yīng)的數(shù)據(jù)
     */
    public <T> List<T> getCacheList(final String key)
    {
        return redisTemplate.opsForList().range(key, 0, -1);
    }
    /**
     * 緩存Set
     *
     * @param key 緩存鍵值
     * @param dataSet 緩存的數(shù)據(jù)
     * @return 緩存數(shù)據(jù)的對象
     */
    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
    {
        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
        Iterator<T> it = dataSet.iterator();
        while (it.hasNext())
        {
            setOperation.add(it.next());
        }
        return setOperation;
    }
    /**
     * 獲得緩存的set
     *
     * @param key
     * @return
     */
    public <T> Set<T> getCacheSet(final String key)
    {
        return redisTemplate.opsForSet().members(key);
    }
    /**
     * 緩存Map
     *
     * @param key
     * @param dataMap
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
    {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
        }
    }
    /**
     * 獲得緩存的Map
     *
     * @param key
     * @return
     */
    public <T> Map<String, T> getCacheMap(final String key)
    {
        return redisTemplate.opsForHash().entries(key);
    }
    /**
     * 往Hash中存入數(shù)據(jù)
     *
     * @param key Redis鍵
     * @param hKey Hash鍵
     * @param value 值
     */
    public <T> void setCacheMapValue(final String key, final String hKey, final T value)
    {
        redisTemplate.opsForHash().put(key, hKey, value);
    }
    /**
     * 獲取Hash中的數(shù)據(jù)
     *
     * @param key Redis鍵
     * @param hKey Hash鍵
     * @return Hash中的對象
     */
    public <T> T getCacheMapValue(final String key, final String hKey)
    {
        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
        return opsForHash.get(key, hKey);
    }
    /**
     * 刪除Hash中的數(shù)據(jù)
     * 
     * @param key
     * @param hkey
     */
    public void delCacheMapValue(final String key, final String hkey)
    {
        HashOperations hashOperations = redisTemplate.opsForHash();
        hashOperations.delete(key, hkey);
    }
    /**
     * 獲取多個Hash中的數(shù)據(jù)
     *
     * @param key Redis鍵
     * @param hKeys Hash鍵集合
     * @return Hash對象集合
     */
    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
    {
        return redisTemplate.opsForHash().multiGet(key, hKeys);
    }
    /**
     * 獲得緩存的基本對象列表
     *
     * @param pattern 字符串前綴
     * @return 對象列表
     */
    public Collection<String> keys(final String pattern)
    {
        return redisTemplate.keys(pattern);
    }
}

將字符串渲染到客戶端工具類

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class WebUtils
{
    /**
     * 將字符串渲染到客戶端
     * 
     * @param response 渲染對象
     * @param string 待渲染的字符串
     * @return null
     */
    public static String renderString(HttpServletResponse response, String string) {
        try
        {
            response.setStatus(200);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            response.getWriter().print(string);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        return null;
    }
}

SQL語句創(chuàng)建用戶表

CREATE TABLE `sys_user` (
  `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `user_name` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT '用戶名',
  `nick_name` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT '昵稱',
  `password` VARCHAR(64) NOT NULL DEFAULT 'NULL' COMMENT '密碼',
  `status` CHAR(1) DEFAULT '0' COMMENT '賬號狀態(tài)(0正常 1停用)',
  `email` VARCHAR(64) DEFAULT NULL COMMENT '郵箱',
  `phonenumber` VARCHAR(32) DEFAULT NULL COMMENT '手機(jī)號',
  `sex` CHAR(1) DEFAULT NULL COMMENT '用戶性別(0男,1女,2未知)',
  `avatar` VARCHAR(128) DEFAULT NULL COMMENT '頭像',
  `user_type` CHAR(1) NOT NULL DEFAULT '1' COMMENT '用戶類型(0管理員,1普通用戶)',
  `create_by` BIGINT(20) DEFAULT NULL COMMENT '創(chuàng)建人的用戶id',
  `create_time` DATETIME DEFAULT NULL COMMENT '創(chuàng)建時間',
  `update_by` BIGINT(20) DEFAULT NULL COMMENT '更新人',
  `update_time` DATETIME DEFAULT NULL COMMENT '更新時間',
  `del_flag` INT(11) DEFAULT '0' COMMENT '刪除標(biāo)志(0代表未刪除,1代表已刪除)',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用戶表'

配置文件

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/你的數(shù)據(jù)庫名稱?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8
    username: ****
    password: ****
  redis:
    # Redis服務(wù)器地址
    host:  127.0.0.1
    # Redis服務(wù)器連接端口
    port: 6379
    # Redis服務(wù)器連接密碼
    password:
    # Redis數(shù)據(jù)庫索引
    database: 3
    # 連接超時時間(毫秒)
    timeout: 30000
    lettuce:
      pool:
        max-active: 50
        max-wait: -1
        max-idle: 50
        min-idle: 1

編碼實(shí)現(xiàn)

目錄結(jié)構(gòu)
關(guān)于Email的類不用管

配置類
RedisConfig類

package com.zzuli.common.config;
import com.zzuli.common.utils.FastJsonRedisSerializer;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
public class RedisConfig {
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
    {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);
        // 使用StringRedisSerializer來序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);
        // Hash的key也采用StringRedisSerializer的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);
        template.afterPropertiesSet();
        return template;
    }
}

SecurityConfig

package com.zzuli.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
 * @author niuben
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //創(chuàng)建BCryptPasswordEncoder注入容器
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //關(guān)閉csrf
                .csrf().disable()
                //不通過Session獲取SecurityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 對于登錄接口 允許匿名訪問
                .antMatchers("/user/login").anonymous()
                // 除上面外的所有請求全部需要鑒權(quán)認(rèn)證
                .anyRequest().authenticated();
    }
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

實(shí)體類
User類

package com.zzuli.pojo;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
 * 用戶表(User)實(shí)體類
 *
 * @author 三更
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("sys_user")   //數(shù)據(jù)庫的用戶名名稱
public class User implements Serializable {
    private static final long serialVersionUID = -40356785423868312L;
    /**
    * 主鍵
    */
    @TableId
    private Long id;
    /**
    * 用戶名
    */
    private String userName;
    /**
    * 昵稱
    */
    private String nickName;
    /**
    * 密碼
    */
    private String password;
    /**
    * 賬號狀態(tài)(0正常 1停用)
    */
    private String status;
    /**
    * 郵箱
    */
    private String email;
    /**
    * 手機(jī)號
    */
    private String phonenumber;
    /**
    * 用戶性別(0男,1女,2未知)
    */
    private String sex;
    /**
    * 頭像
    */
    private String avatar;
    /**
    * 用戶類型(0管理員,1普通用戶)
    */
    private String userType;
    /**
    * 創(chuàng)建人的用戶id
    */
    private Long createBy;
    /**
    * 創(chuàng)建時間
    */
    private Date createTime;
    /**
    * 更新人
    */
    private Long updateBy;
    /**
    * 更新時間
    */
    private Date updateTime;
    /**
    * 刪除標(biāo)志(0代表未刪除,1代表已刪除)
    */
    private Integer delFlag;
}

UserLogin
繼承UserDetails

package com.zzuli.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
/**
 * @author niuben
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
public class UserLogin implements UserDetails {
    private User user;
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }
    @Override
    public String getPassword() {
        return user.getPassword();
    }
    @Override
    public String getUsername() {
        return user.getUserName();
    }
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return true;
    }
}

接口實(shí)現(xiàn)類
LoginController接口

package com.zzuli.controller;
import com.zzuli.common.api.CommonResult;
import com.zzuli.pojo.User;
import com.zzuli.service.LoginService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
 * @author niuben
 */
@RestController
public class LoginController {
    @Resource
    private LoginService loginService;
    @PostMapping("/user/login")
    public CommonResult<Object> login(@RequestBody User user){
        CommonResult<Object> result = null;
        try {
            result = loginService.login(user);
        } catch (Exception e) {
           return CommonResult.success("賬戶或者密碼錯誤!");
        }
        return result;
    }
}

UserDetailsServiceImpl實(shí)現(xiàn)類

package com.zzuli.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zzuli.mapper.UserMapper;
import com.zzuli.pojo.User;
import com.zzuli.pojo.UserLogin;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Objects;
/**
 * @author niuben
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Resource
    private UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //查詢用戶信息
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>();
        queryWrapper.eq(User::getUserName,username);
        User user = userMapper.selectOne(queryWrapper);
        //如果沒有查詢到用戶,就拋出異常
        if(Objects.isNull(user)){
            throw new RuntimeException("用戶名或者密碼錯誤!");
        }
        //將數(shù)據(jù)封裝成UserDetails
        return new UserLogin(user);
    }
}

LoginService接口

package com.zzuli.service;
import com.zzuli.common.api.CommonResult;
import com.zzuli.pojo.User;
/**
 * @author niuben
 */
public interface LoginService {
    CommonResult<Object> login(User user);
}

LoginService實(shí)現(xiàn)接口

package com.zzuli.service.impl;
import com.zzuli.common.api.CommonResult;
import com.zzuli.common.utils.JwtUtil;
import com.zzuli.common.utils.RedisCache;
import com.zzuli.pojo.User;
import com.zzuli.pojo.UserLogin;
import com.zzuli.service.LoginService;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
 * @author niuben
 */
@Service
public class LoginServiceImpl implements LoginService {
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private RedisCache redisCache;
    @Override
    public CommonResult<Object> login(User user) {
        //進(jìn)行用戶認(rèn)證
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        //認(rèn)證未通過,給出提示
        if(Objects.isNull(authenticate)){
            throw new RuntimeException("登陸失?。?);
        }
        //通過了,生成jwt
        UserLogin loginUser = (UserLogin) authenticate.getPrincipal();
        String id = loginUser.getUser().getId().toString();
        String jwt = JwtUtil.createJWT(id);
        Map<String,String> map = new HashMap<>();
        map.put("token",jwt);
        //將用戶信息存入redis
        redisCache.setCacheObject("login"+id,loginUser);
        return CommonResult.success(map,"登陸成功!");
    }
}

UserMapper

package com.zzuli.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zzuli.pojo.User;
public interface UserMapper extends BaseMapper<User> {
}

啟動類

package com.zzuli;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.zzuli.mapper")  //mapper掃描器
public class AppleunlockManageApplication {
    public static void main(String[] args) {
        SpringApplication.run(AppleunlockManageApplication.class, args);
    }
}

效果展示

注意:測試時要打開redis,數(shù)據(jù)庫中的密碼必須是加密后的
可以使用一下方法進(jìn)行加密,passwordEncoderSecurityConfig中已經(jīng)注入的

   @Resource
    private PasswordEncoder passwordEncoder;
	String encode = passwordEncoder.encode("123456");
    System.out.println(encode);

登錄接口測試

到此這篇關(guān)于Spring-Security實(shí)現(xiàn)登錄接口流程的文章就介紹到這了,更多相關(guān)Spring-Security登錄接口內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java爬蟲之使用HttpClient模擬瀏覽器發(fā)送請求方法詳解

    java爬蟲之使用HttpClient模擬瀏覽器發(fā)送請求方法詳解

    這篇文章主要介紹了java爬蟲之使用HttpClient模擬瀏覽器發(fā)送請求方法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • RocketMQ源碼解析topic創(chuàng)建機(jī)制詳解

    RocketMQ源碼解析topic創(chuàng)建機(jī)制詳解

    這篇文章主要為大家介紹了RocketMQ源碼解析topic創(chuàng)建機(jī)制詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分庫分表

    SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分庫分表

    本文主要介紹了SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分庫分表,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • SpringBoot與SpringSecurity整合方法附源碼

    SpringBoot與SpringSecurity整合方法附源碼

    這篇文章主要介紹了SpringBoot與SpringSecurity整合,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • java數(shù)組算法例題代碼詳解(冒泡排序,選擇排序,找最大值、最小值,添加、刪除元素等)

    java數(shù)組算法例題代碼詳解(冒泡排序,選擇排序,找最大值、最小值,添加、刪除元素等)

    這篇文章主要介紹了java數(shù)組算法例題代碼詳解(冒泡排序,選擇排序,找最大值、最小值,添加、刪除元素等),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-05-05
  • JAVA熔斷和降級真實(shí)關(guān)系的圖文詳解

    JAVA熔斷和降級真實(shí)關(guān)系的圖文詳解

    這篇文章主要介紹了Java熔斷和降級的關(guān)系,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Java中synchronized鎖升級的過程

    Java中synchronized鎖升級的過程

    本文主要介紹了Java中synchronized鎖升級的過程,synchronized相對于早期的synchronized做出了優(yōu)化,從以前的加鎖就是重量級鎖優(yōu)化成了有一個鎖升級的過,下文詳細(xì)內(nèi)容需要的小伙伴可以參考一下
    2022-05-05
  • Java快速排序及求數(shù)組中第k小的值解析

    Java快速排序及求數(shù)組中第k小的值解析

    這篇文章主要介紹了Java快速排序及求數(shù)組中第k小的值解析,選一個中間值,把數(shù)組中比它小的元素放到左邊,比它大的元素放到右邊,這時形成三個子數(shù)組,分別是中間值,比它大的數(shù)和比它小的數(shù),然后對前后兩個數(shù)組進(jìn)行遞歸,需要的朋友可以參考下
    2023-11-11
  • Spring Boot Maven插件使用詳解

    Spring Boot Maven插件使用詳解

    這篇文章主要為大家詳細(xì)介紹了Spring Boot Maven插件使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • SpringBoot實(shí)現(xiàn)統(tǒng)一封裝返回前端結(jié)果集的示例代碼

    SpringBoot實(shí)現(xiàn)統(tǒng)一封裝返回前端結(jié)果集的示例代碼

    在實(shí)際項目開發(fā)過程中,我們經(jīng)常將返回數(shù)據(jù)的基本形式統(tǒng)一為JSON格式的數(shù)據(jù)。但項目可能是由很多人開發(fā)的,所以我們最好將返回的結(jié)果統(tǒng)一起來。本文介紹了SpringBoot實(shí)現(xiàn)統(tǒng)一封裝返回前端結(jié)果集的示例代碼,需要的可以參考一下
    2022-06-06

最新評論

博罗县| 新干县| 平顶山市| 阜新| 津南区| 吉木乃县| 临沧市| 阜宁县| 自贡市| 永靖县| 兴和县| 杭锦后旗| 新津县| 永福县| 宁陕县| 武威市| 固原市| 徐汇区| 武乡县| 拜泉县| 博爱县| 北流市| 布拖县| 思茅市| 隆昌县| 剑阁县| 科尔| 个旧市| 桃园县| 灌云县| 焉耆| 德安县| 招远市| 长葛市| 台南市| 威宁| 石渠县| 铁岭县| 纳雍县| 河曲县| 理塘县|