spring boot之 springSecurity 结合JWT

package shang.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.OncePerRequestFilter;
import shang.handle.*;
import shang.service.UserDetailsServiceImpl;

import javax.sql.DataSource;

/**
 * @Auther: 三尾鱼
 * @Date: 2020/11/23 08:51
 * @Description:
 */
//@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
//开启注解方式,的鉴权判断,
// 其中securedEnabled = true 是基于角色的注解;
//prePostEnabled = true 是基于access表达式的注解,即可以角色,又可以权限因子
@Configuration
public class SecurityConfig02 extends WebSecurityConfigurerAdapter
{

    /* @Autowired
     DataSource dataSource;
 */
    @Autowired
    UserDetailsServiceImpl userDetailsServiceImpl;

    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception
    {
        auth.userDetailsService (userDetailsServiceImpl).passwordEncoder (passwordEncoder ());
    }

    //要实现自定义登录页面,必须继承 WebSecurityConfigurerAdapter 并且重写 configure(HttpSecurity http)

    /**
     * anyRequest          |   匹配所有请求路径
     * access              |   SpringEl表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyAll             |   用户不能访问
     * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
     * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
     * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
     * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
     * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
     * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
     * permitAll           |   用户可以任意访问
     * rememberMe          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        http.cors ().and ().csrf ().disable ()
                //不要session
                .sessionManagement ().sessionCreationPolicy (SessionCreationPolicy.STATELESS);

        //未登陆时返回 JSON 格式的数据给前端,否则是html
        http.httpBasic ().authenticationEntryPoint (restAuthenticationEntryPoint);

       http.formLogin ()//表单提交
                .usernameParameter ("username123")//自定义如蝉,缺省是username 和 password
                .passwordParameter ("password123")//如果登录页面中没有,登录都会失败

                .loginPage ("/login")//自定义登录页面 都不要带后缀
                //还要指定自定义登录的URL,必须和表单提交的接口一样,这样才能触发自定义登录逻辑
                .loginProcessingUrl ("/login")//url /login 是login.html 页面的action

                //.successForwardUrl ("/toSuccess")//登录成功后,跳转的URL,需要post请求
                //.successForwardUrl ("http://www.baidu.com")//这种方式行不通
                //.successHandler (new 自定义成功跳转逻辑类 ("http://www.baidu.com"))
                .successHandler (new 登录成功处理器 ("/toSuccess"))//登录成功处理器
                //真正的前后端分离开发,这里无论成功与否,都返回JSON字符串和令牌,让前端自己决定如何处理
                //.failureForwardUrl ("/toError");//登录失败,跳转的URL ,需要post请求
                .failureHandler (new 登录失败处理器 (""));//登录失败处理器

        // 【异常处理】之 鉴权失败处理器 要另起一行单独配置
        http.exceptionHandling ().accessDeniedHandler (new 鉴权失败处理器 ());


        //加入自定义授权过滤器
        http.addFilter (new JWTAuthorizationFilter (authenticationManager ()));

        //实践证明:如果不把凭证放进spring security的上下文,将访问不到任何需要认证才放行的URL,
        // 自定义此拦截器的就是为了在每次请求都把Head中的token解密后的用户凭证放进上下文
        //至于权限验证,交给框架完成,当然如果你想自定义就覆盖框架的相应过滤器
        //这2个过滤器是等价的
        //http.addFilterBefore (new 每次请求拦截一次过滤器 (), UsernamePasswordAuthenticationFilter.class);


        //开启记住我  功能
        /*http.rememberMe ()
                //设置数据源
                .tokenRepository (persistentTokenRepository ())
                //设置超时时间,缺省是2周,这里设置60秒
                .tokenValiditySeconds (60)
                //自定义登录逻辑,必选项
                .userDetailsService (userDetailsServiceImpl);*/

        //退出配置
        http.logout ()
                //退出成功后,跳转的页面
                .logoutSuccessUrl ("/login");

        //授权
        http.authorizeRequests ()
                //antMatchers方法中的通配符?=任何一个字符 *=任意多个字符 **=任意多个目录
                //.antMatchers ("/js/**", "/css/**", "/img/**").permitAll () //放行所有静态资源
                //.antMatchers ("/**/*.png").permitAll () //放行所有后缀是png的图片资源
                .regexMatchers (".+\\.png").permitAll () //使用正则表达式匹配
                .regexMatchers (HttpMethod.POST, "/demo").permitAll () //必须是post请求

                .antMatchers ("/login").permitAll ()//必须放行登录URL,否则会报 重定向次数过多
                .antMatchers ("/toError").permitAll ()//必须放行登录失败的URL,否则会报 重定向次数过多

                //.antMatchers ("/admin").hasAuthority ("admin")//严格区分大小写,基于权限因子的访问控制
                //.antMatchers ("/admin").hasAnyAuthority ("admin","Admin")
                //hasAnyAuthority 严格区分大小写,基于权限因子的访问控制,有任意一个权限因子都可以访问

                //基于角色的访问控制,严格区分大小写,授权失败,如何返回JSON字符串
                //.antMatchers ("/admin").hasAnyRole ("Admin","useR")//注意点:角色名,不用添加前缀【ROLE_】
                //.antMatchers ("/admin").access ("hasAnyRole('admin1','user1')")


                //基于IP地址的访问控制
                //.antMatchers ("/admin").hasIpAddress ("227.0.0.1")

                //所有请求都必须认证,就是必须登录,才能访问
                .anyRequest ().authenticated ();

        //自定义的access方法
        //.anyRequest ().access ("@myAccessControImpl.hasPermission(request,authentication)");
    }

    @Bean
    PasswordEncoder passwordEncoder()
    {
        return new BCryptPasswordEncoder ();
    }

    //记住我的时候,添加的这个
    /*@Bean
    public PersistentTokenRepository persistentTokenRepository()
    {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl ();
        //设置数据源
        tokenRepository.setDataSource (dataSource);
        //设置 自动建表,第一次使用,第二次注释,否则每次建表会覆盖掉原来记录
        tokenRepository.setCreateTableOnStartup (false);
        return tokenRepository;
    }*/

    //容许跨站请求
    @Bean
    CorsConfigurationSource corsConfigurationSource()
    {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource ();
        source.registerCorsConfiguration ("/**", new CorsConfiguration ().applyPermitDefaultValues ());
        return source;
    }
}
package shang.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import shang.entity.JsonMsg;

/**
* @Auther: 三尾鱼
* @Date: 2021/2/19 12:33
* @Description:
*/

@Controller
public class HomeController
{
@RequestMapping("/login")
public ModelAndView login(ModelAndView mv)
{
mv.setViewName ("/login");//设置视图名
return mv;
}


//@Secured ("ROLE_user3")
//@PreAuthorize ("hasRole('user')")
//@PreAuthorize ("hasRole('ROLE_user')") //可以使用ROLE_ 前缀
@PreAuthorize ("hasAnyAuthority('admin','user')")//基于权限因子的 鉴权
@RequestMapping("/toSuccess")
public ModelAndView toSuccess(ModelAndView mv)
{
mv.setViewName ("/main");//设置视图名
return mv;
}

// @RequestMapping("/toError")
// public ModelAndView toError(ModelAndView mv)
// {
// mv.setViewName ("/error");
// 设置视图名,如果templates下面有特别error.html 页面,发生权限不够,将自动关联到error.html
//如果没有error.html 将显示403
// return mv;
// }

@RequestMapping("/demo")
@ResponseBody
public JsonMsg demo()
{
JsonMsg jsonMsg =new JsonMsg ();
jsonMsg.setMsg ("张三");
jsonMsg.setStatusCode (200);
return jsonMsg;
}
@PreAuthorize ("hasAnyAuthority('admin','user33')")//基于权限因子的 鉴权
@RequestMapping("/admin")
public String admin(){
return "admin";
}

@RequestMapping("/showspringsecurity5")
public String show_springsecurity5(){
return "show-springsecurity5";
}
}

package shang.handle;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

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.ArrayList;

/**
* @Auther: Administrator
* @Date: 2021/2/21 14:19
* @Description:
*/
public class JWTAuthorizationFilter extends BasicAuthenticationFilter
{

public JWTAuthorizationFilter(AuthenticationManager authenticationManager)
{
super (authenticationManager);
}

@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws IOException, ServletException
{

//String tokenHeader = "123";//request.getHeader(JwtTokenUtils.TOKEN_HEADER);
// 如果请求头中没有Authorization信息则直接放行了
//if (tokenHeader == null || !tokenHeader.startsWith(JwtTokenUtils.TOKEN_PREFIX)) {
/* if (tokenHeader == null || tokenHeader.equals ("123"))
{
//抛出鉴权失败异常
//throw new AccessDeniedException("403,无token");
//实践怎么,拿不到token,就返回到登陆页面
chain.doFilter (request, response);
return;
}*/
//chain.doFilter (request, response);
// 如果请求头中有token,则进行解析,并且设置认证信息
//SecurityContextHolder.getContext ().setAuthentication (getAuthentication (tokenHeader));
//super.doFilterInternal (request, response, chain);
//测试做个简易版
String authHeader =null;
try
{
authHeader =request.getHeader("token");//Authorization

//token里面包含有1、用户名 2、权限因子和角色
if (authHeader == null || authHeader.trim ().length () == 0)
{
}
else {
String username = "admin";
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken (username, null, AuthorityUtils.commaSeparatedStringToAuthorityList
("admin,normal,ROLE_admin,ROLE_user,/toSuccess,/insert,/delete"));
SecurityContextHolder.getContext().setAuthentication(authentication);
}


//new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities ());
}catch (AuthenticationException e) {
System.out.println ("AuthenticationException="+e.getMessage ());
}
finally
{
//实践证明:如果不把凭证放进spring security的上下文,将访问不到任何需要认证才放行的URL,
// 自定义此拦截器的就是为了在每次请求都把Head中的token解密后的用户凭证放进上下文
//至于权限验证,交给框架完成,当然如果你想自定义就覆盖框架的相应过滤器
chain.doFilter(request, response);//如果上下文有认证信息,就跳过认证页面进入鉴权,如果没有认证信息,直接重定向到认证页面
}
}

// 这里从token中获取用户信息并新建一个token
private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader)
{
String token = "123";// tokenHeader.replace(JwtTokenUtils.TOKEN_PREFIX, "");
String username = "admin";// JwtTokenUtils.getUsername(token);
if (username != null)
{
return new UsernamePasswordAuthenticationToken (username, null, new ArrayList<> ());
}
return null;
}
}

package shang.handle;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import shang.entity.JsonMsg;

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

/**
 * @Auther: Administrator
 * @Date: 2021/2/21 19:49
 * @Description:这里为了之后结果更直观,自定义一个AuthenticationEntryPoint,
 * 用于在未登录是访问接口返回json而不是login.html
 * 当未登录或者token失效访问接口时,自定义的返回结果
 */
@Component
public class RestAuthenticationEntryPoint  implements AuthenticationEntryPoint
{
      @Override
      public void commence(HttpServletRequest httpServletRequest,
                           HttpServletResponse response, AuthenticationException e) throws IOException, ServletException
      {
            response.setCharacterEncoding("UTF-8");//设置编码格式
            response.setContentType("application/json");
            JsonMsg jsonMsg =new JsonMsg ();
            jsonMsg.setMsg (" AuthenticationException 【尚未登录,或者登录过期】触发了-->"+e.getMessage());
            jsonMsg.setStatusCode (403);
            //Jackson
            ObjectMapper mapper = new ObjectMapper ();
            String msgJson=mapper.writeValueAsString (jsonMsg);
            //response.getWriter().println(JSON.toJSONString(Result.error().message("尚未登录,或者登录过期   " + e.getMessage())));
            response.getWriter ().print (msgJson);
            response.getWriter().flush();
      }
}
package shang.handle;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import shang.entity.JsonMsg;

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

/**
 * @Auther: 三尾鱼
 * @Date: 2021/2/19 14:54
 * @Description:
 */
public class 登录失败处理器 implements AuthenticationFailureHandler
{
    private String url;


    public 登录失败处理器(String url)
    {
        this.url = url;
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest,
                                        HttpServletResponse httpServletResponse,
                                        AuthenticationException e) throws IOException, ServletException
    {
        //httpServletResponse.sendRedirect (url);
        JsonMsg jsonMsg =new JsonMsg ();
        jsonMsg.setMsg ("自定义失败处理器 onAuthenticationFailure 触发了");
        jsonMsg.setStatusCode (302);
        //Jackson
        ObjectMapper mapper = new ObjectMapper ();

        String msgJson=mapper.writeValueAsString (jsonMsg);
        //有中文乱码,设置一下
        httpServletResponse.setHeader("Content-type", "application/json;charset=UTF-8");

        //OutputStream ps = httpServletResponse.getOutputStream ();
        //这句话的意思,使得放入流的数据是utf8格式
        //ps.write (personJson.getBytes (StandardCharsets.UTF_8));
        httpServletResponse.getWriter ().print (msgJson);
        //httpServletResponse.sendRedirect (url);
    }
}
package shang.handle;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import shang.entity.JsonMsg;

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

/**
 * @Auther: 三尾鱼
 * @Date: 2021/2/19 14:36
 * @Description:
 */
public class 登录成功处理器 implements AuthenticationSuccessHandler
{
    private String url;

    public 登录成功处理器(String url)
    {
        this.url = url;
    }

    /*@Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        FilterChain chain,
                                        Authentication authentication) throws IOException, ServletException
    {

    }*/

    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,
                                        HttpServletResponse httpServletResponse,
                                        Authentication authentication) throws IOException, ServletException
    {
        User user = (User) authentication.getPrincipal ();
        System.out.println (user.getUsername ());
        System.out.println (user.getPassword ());
        System.out.println (user.getAuthorities ());//权限列表,就是UserDetailsServiceImpl放进去的【权限、角色】 数据

        System.out.println (httpServletRequest.getRemoteAddr ());

        JsonMsg jsonMsg =new JsonMsg ();
        jsonMsg.setMsg ("onAuthenticationSuccess 触发了--token:"+"abcd1234admin");
        jsonMsg.setStatusCode (200);
        //Jackson
        ObjectMapper mapper = new ObjectMapper ();

        String personJson=mapper.writeValueAsString (jsonMsg);
        //有中文乱码,设置一下
        httpServletResponse.setHeader("Content-type", "application/json;charset=UTF-8");

        //OutputStream ps = httpServletResponse.getOutputStream ();
        //这句话的意思,使得输出流的数据是utf8格式
        //ps.write (personJson.getBytes (StandardCharsets.UTF_8));
        httpServletResponse.getWriter ().print (personJson);

        //httpServletResponse.sendRedirect (url);
    }
}
package shang.handle;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * @Auther: 三尾鱼
 * @Date: 2021/2/19 17:26
 * @Description: 前后端分离的开发 都是要返回JSON
 */
public  class 鉴权失败处理器 implements AccessDeniedHandler
{
    @Override
    public void handle(HttpServletRequest httpServletRequest,
                       HttpServletResponse httpServletResponse,
                       AccessDeniedException e) throws IOException, ServletException
    {
        httpServletResponse.setStatus (httpServletResponse.SC_FORBIDDEN);//403

        //有中文乱码,设置一下
        httpServletResponse.setHeader("Content-type", "application/json;charset=UTF-8");
        PrintWriter pw=httpServletResponse.getWriter ();
        Map<String,Object> map=new HashMap<String,Object> ();
        map.put ("status",403);
        map.put ("msg", "权限不够,请联系管理员");
        ObjectMapper mapper = new ObjectMapper ();

        String JsonStr=mapper.writeValueAsString(map);
        pw.write (JsonStr);
        //pw.write ("{\"status\":\"error\",\"msg\":\"权限不够,请联系管理员\"}  ");
        pw.flush ();
        pw.close();
    }
}
package shang.service;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @Auther: Administrator
 * @Date: 2021/2/21 19:37
 * @Description:
 */

@Component
public class JwtUtils
{
      private static final String CLAIM_KEY_USERNAME = "sub";
      private static final String CLAIM_KEY_CREATED = "created";
      @Value("${jwt.secret}")
      private String secret;
      @Value("${jwt.expiration}")
      private Long expiration;

      // 创建token
      public String generateToken(String username)
      {
            return Jwts.builder ()
                    .signWith (SignatureAlgorithm.HS512, secret)
                    .setSubject (username)
                    .setIssuedAt (new Date ())
                    .setExpiration (new Date (System.currentTimeMillis () + expiration * 1000))
                    .compact ();

      }

      // 从token中获取用户名
      public String getUserNameFromToken(String token)
      {
            return getTokenBody (token).getSubject ();
      }

      // 是否已过期
      public boolean isExpiration(String token)
      {
            return getTokenBody (token).getExpiration ().before (new Date ());
      }

      private Claims getTokenBody(String token)
      {
            return Jwts.parser ()
                    .setSigningKey (secret)
                    .parseClaimsJws (token)
                    .getBody ();
      }
}
package shang.service;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

/**
 * @Auther: 三尾鱼
 * @Date: 2020/11/24 12:20
 * @Description:
 * USE ipranDB
 * GO
 * CREATE UNIQUE NONCLUSTERED               --唯一 非聚集
 * INDEX  username_唯一_user on         --索引名称
 * [ipranDB].[dbo].[user]   --表名称
 * (username)                  -- 表的字段名称CREATE UNIQUE NONCLUSTERED               --唯一 非聚集
 * GO
 *
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService
{
    @Autowired
    PasswordEncoder passwordEncoder;
    @Override
    public UserDetails loadUserByUsername(String username
                                            //username 是前端传递过来的
                                         ) throws UsernameNotFoundException
    {
        System.out.println ("执行了自定义登录逻辑!!");
        //这里注入数据库访问类,可以改造成按数据库验证账号和口令
        //需要从数据库获取的信息有:1、用户名,2、加密后的口令 3、权限因子或角色

        //1、根据用户名到数据库去查询,返回UserDetails的实现类
        /*User user;
        if (user == null)
        {
            throw new UsernameNotFoundException ("用户不存在!");
        }*/

        if(!"admin".equals (username)){
            throw new UsernameNotFoundException ("用户不存在!");
        }

        //2、比较密码(注册时已经加密过),如果匹配成功返回UserDetails,
        String password=passwordEncoder.encode("123");
        //从数据库获取当前用户的所有角色
        //3、这里的user是org.springframework.security.core.userdetails.User 它实现了UserDetails接口
        //这里的"admin,normal"是权限因子,如果是角色,必须是【ROLE_】前缀开头,例如  ROLE_admin,ROLE_user
        return new User (username, password, AuthorityUtils.commaSeparatedStringToAuthorityList
                ("admin,normal,ROLE_admin,ROLE_user,/toSuccess,/insert,/delete"));
        //user.setRoles (userMapper.getUserRolesByUid (user.getId ()));
        //return user;
    }
}
package shang.service;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;

/**
 * @Auther: 三尾鱼
 * @Date: 2021/2/20 09:34
 * @Description:
 */
@Service
public class MyAccessControImpl implements I自定义权限控制接口
{
    //类名,不可写中文,否则配置不进去
    @Override
    public boolean hasPermission(HttpServletRequest request,
                                 Authentication authentication)
    {
        Object principal = authentication.getPrincipal ();
        if (principal instanceof UserDetails)
        {
            UserDetails userDetails = (UserDetails) principal;
            //获取当前登录用户的授权集合列表
            Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities ();
            return authorities.contains (new SimpleGrantedAuthority (request.getRequestURI ()));//基于访问URL的权限控制
        }

        return false;
    }
}
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver

      #指定url,xxx是数据库的名字,serverTimezone=Asia/Shanghai 解决时区问题,&useUnicode=true&characterEncoding=utf-8指定字符的编码集
#      jdbc-url: jdbc:mysql://localhost:3306/ipran_db?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
#      username: root
#      password: aatl?451
    url: jdbc:mysql://localhost:3306/ipran_db?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
    username: root
    password: aatl?451

jwt:
  tokenHeader: Authorization #JWT存储的请求头
  secret: my-springsecurity-plus #JWT加解密使用的密钥
  expiration: 604800 #JWT的超期限时间(60*60*24*7)
  tokenHead: 'Bearer ' #JWT负载中拿到开头,空格别忘了

 

  

posted on 2021-02-22 12:55  湖北笨笨  阅读(246)  评论(0编辑  收藏  举报