2023-03-23 springSecurity登錄實現(xiàn)

一、編寫UserDetailService類實現(xiàn)UserDetailsService接口

package com.zh.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zh.domain.entity.LoginUser;
import com.zh.domain.entity.User;
import com.zh.mapper.UserMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
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 java.util.Objects;

/**
 * 用來查詢數(shù)據(jù)庫用戶的類
 */
@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1.查詢用戶
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserName,username);
        User user = userMapper.selectOne(queryWrapper);
        //2.沒查到,拋出異常
        if (Objects.isNull(user)){
            throw new RuntimeException("用戶不存在");
        }
        //3.todo 查詢用戶權(quán)限
        //4.返回用戶信息
        return new LoginUser(user);
    }
}

二、在controller對應(yīng)的service實現(xiàn)類里面

package com.zh.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zh.domain.ResponseResult;
import com.zh.domain.entity.LoginUser;
import com.zh.domain.entity.User;
import com.zh.domain.vo.BlogUserLoginVo;
import com.zh.domain.vo.UserInfoVo;
import com.zh.mapper.UserMapper;
import com.zh.service.BlogLoginService;
import com.zh.utils.BeanCopyUtils;
import com.zh.utils.JwtUtil;
import com.zh.utils.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import java.util.Objects;

import static com.zh.constants.SystemConstants.LOGIN;

/**
 * 用戶表(User)表服務(wù)實現(xiàn)類
 *
 * @author makejava
 * @since 2023-03-23 16:57:42
 */
@Service
public class BlogLoginServiceImpl extends ServiceImpl<UserMapper, User> implements BlogLoginService {

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Override
    public ResponseResult login(User user) {

        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
        // 這個方法會調(diào)用UserDetailServiceImpl里面的方法去查詢數(shù)據(jù)庫,將結(jié)果返回給authenticate
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        if (Objects.isNull(authenticate)){
            throw  new RuntimeException("密碼錯誤");
        }

        //得到用戶id,生成token
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        String userId = loginUser.getUser().getId().toString();
        String jwt = JwtUtil.createJWT(userId);
        //存入redis
        redisCache.setCacheObject(LOGIN+userId,loginUser);
        //將token和userInfo封裝凑队、返回
        UserInfoVo userInfoVo = BeanCopyUtils.copyBean(loginUser.getUser(), UserInfoVo.class);
        BlogUserLoginVo blogUserLoginVo = new BlogUserLoginVo(jwt, userInfoVo);
        return ResponseResult.okResult(blogUserLoginVo);
    }
}

三、編寫JwtAuthenticationTokenFilter過濾器

這個過濾器要配置在UsernamePasswordAuthenticationFilter過濾器之前幔翰,在securityConfig配置文件中配置

package com.zh.filter;

import com.alibaba.fastjson.JSON;
import com.zh.domain.ResponseResult;
import com.zh.domain.entity.LoginUser;
import com.zh.domain.vo.BlogUserLoginVo;
import com.zh.enums.AppHttpCodeEnum;
import com.zh.utils.JwtUtil;
import com.zh.utils.RedisCache;
import com.zh.utils.WebUtils;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

import static com.zh.constants.SystemConstants.LOGIN;

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private RedisCache redisCache;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterchain) throws ServletException, IOException {
        //1.拿到請求頭token
        String token = request.getHeader("token");
        if (!StringUtils.hasText(token)){
            //說明該接口不需要登錄  直接放行
            filterchain.doFilter(request,response);
            return;
        }
        //2.解析token漩氨,拿到用戶id
        Claims claims = null;
        try {
            claims = JwtUtil.parseJWT(token);
        } catch (Exception e) {
            e.printStackTrace();
            //超時   token非法
            ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
            WebUtils.renderString(response, JSON.toJSONString(result));
            return;
        }
        //3.從redis獲取用戶信息
        String userId = claims.getSubject();
        LoginUser loginUser = redisCache.getCacheObject(LOGIN + userId);
        if (Objects.isNull(loginUser)){
            //說明登錄過期,需要重新登錄
            ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
            WebUtils.renderString(response,JSON.toJSONString(result));
            return;
        }
        //4.存入SecurityContextHolder
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, null);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //放行
        filterchain.doFilter(request,response);
    }
}

四导匣、securityConfig配置文件

package com.zh.config;

import com.zh.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
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;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Autowired
    AuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    AccessDeniedHandler accessDeniedHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //關(guān)閉csrf
                .csrf().disable()
                //不通過Session獲取SecurityContext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 對于登錄接口 允許匿名訪問
                .antMatchers("/login").anonymous()
                // 除上面外的所有請求全部不需要認(rèn)證即可訪問
                .anyRequest().permitAll();
        http.exceptionHandling()
                        .authenticationEntryPoint(authenticationEntryPoint)
                                .accessDeniedHandler(accessDeniedHandler);


        http.logout().disable();
        //配置JwtAuthenticationTokenFilter過濾器
http.addFilterBefore(jwtAuthenticationTokenFilter,UsernamePasswordAuthenticationFilter.class);
        //允許跨域
        http.cors();
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市茸时,隨后出現(xiàn)的幾起案子贡定,更是在濱河造成了極大的恐慌,老刑警劉巖可都,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缓待,死亡現(xiàn)場離奇詭異,居然都是意外死亡渠牲,警方通過查閱死者的電腦和手機(jī)旋炒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來签杈,“玉大人瘫镇,你說我怎么就攤上這事〈鹄眩” “怎么了铣除?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鹦付。 經(jīng)常有香客問我尚粘,道長,這世上最難降的妖魔是什么敲长? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任郎嫁,我火速辦了婚禮秉继,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘泽铛。我一直安慰自己尚辑,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布厚宰。 她就那樣靜靜地躺著腌巾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铲觉。 梳的紋絲不亂的頭發(fā)上澈蝙,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天,我揣著相機(jī)與錄音撵幽,去河邊找鬼灯荧。 笑死,一個胖子當(dāng)著我的面吹牛盐杂,可吹牛的內(nèi)容都是我干的逗载。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼链烈,長吁一口氣:“原來是場噩夢啊……” “哼厉斟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起强衡,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤擦秽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后漩勤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體感挥,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年越败,在試婚紗的時候發(fā)現(xiàn)自己被綠了触幼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡究飞,死狀恐怖置谦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情亿傅,我是刑警寧澤霉祸,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站袱蜡,受9級特大地震影響丝蹭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一奔穿、第九天 我趴在偏房一處隱蔽的房頂上張望镜沽。 院中可真熱鬧,春花似錦贱田、人聲如沸缅茉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蔬墩。三九已至,卻和暖如春耗拓,著一層夾襖步出監(jiān)牢的瞬間拇颅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工乔询, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留樟插,地道東北人。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓竿刁,卻偏偏與公主長得像黄锤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子食拜,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內(nèi)容