{"id":1153,"date":"2023-11-10T18:17:12","date_gmt":"2023-11-10T10:17:12","guid":{"rendered":"http:\/\/www.max-shu.com\/blog\/?p=1153"},"modified":"2023-11-10T18:17:12","modified_gmt":"2023-11-10T10:17:12","slug":"spring-security%e5%92%8cjwt%e7%bb%93%e5%90%88","status":"publish","type":"post","link":"http:\/\/www.max-shu.com\/blog\/?p=1153","title":{"rendered":"Spring Security\u548cJWT\u7ed3\u5408"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\"><strong>\u5148\u5f15\u5165pom.xml\uff0c\u4e3b\u8981\u770bdependency\u90e8\u5206\uff1a<\/strong><\/h2>\n\n\n\n<p>&lt;parent><br>   &lt;groupId>org.springframework.boot&lt;\/groupId><br>   &lt;artifactId>spring-boot-starter-parent&lt;\/artifactId><br>   &lt;version>3.1.5&lt;\/version><br>   &lt;relativePath\/> <em>&lt;!&#8211; lookup parent from repository &#8211;><br><\/em>&lt;\/parent><br>&lt;groupId>com.maxshu&lt;\/groupId><br>&lt;artifactId>test_SpringSecurity&lt;\/artifactId><br>&lt;version>0.0.1-SNAPSHOT&lt;\/version><br>&lt;name>test_SpringSecurity&lt;\/name><br>&lt;description>test_SpringSecurity&lt;\/description><br>&lt;properties><br>   &lt;java.version>17&lt;\/java.version><br>   &lt;kotlin.version>1.8.22&lt;\/kotlin.version><br>&lt;\/properties><br>&lt;dependencies><br>   &lt;dependency><br>      &lt;groupId>org.springframework.boot&lt;\/groupId><br>      &lt;artifactId>spring-boot-starter-data-jpa&lt;\/artifactId><br>   &lt;\/dependency><br>   &lt;dependency><br>      &lt;groupId>org.jetbrains.kotlin&lt;\/groupId><br>      &lt;artifactId>kotlin-reflect&lt;\/artifactId><br>   &lt;\/dependency><br>   &lt;dependency><br>      &lt;groupId>org.jetbrains.kotlin&lt;\/groupId><br>      &lt;artifactId>kotlin-stdlib&lt;\/artifactId><br>   &lt;\/dependency><br><br>   &lt;dependency><br>      &lt;groupId>com.mysql&lt;\/groupId><br>      &lt;artifactId>mysql-connector-j&lt;\/artifactId><br>      &lt;scope>runtime&lt;\/scope><br>   &lt;\/dependency><br>   &lt;dependency><br>      &lt;groupId>org.projectlombok&lt;\/groupId><br>      &lt;artifactId>lombok&lt;\/artifactId><br>      &lt;optional>true&lt;\/optional><br>   &lt;\/dependency><br>   &lt;dependency><br>      &lt;groupId>org.springframework.boot&lt;\/groupId><br>      &lt;artifactId>spring-boot-starter-test&lt;\/artifactId><br>      &lt;scope>test&lt;\/scope><br>   &lt;\/dependency><br><br>   <em>&lt;!&#8211; Spring Security &#8211;><br>   <\/em>&lt;dependency><br>      &lt;groupId>org.springframework.boot&lt;\/groupId><br>      &lt;artifactId>spring-boot-starter-web&lt;\/artifactId><br>   &lt;\/dependency><br>   &lt;dependency><br>      &lt;groupId>org.springframework.boot&lt;\/groupId><br>      &lt;artifactId>spring-boot-starter-security&lt;\/artifactId><br>   &lt;\/dependency><br><br>   <em>&lt;!&#8211; Hutool JWT &#8211;><br>   <\/em>&lt;dependency><br>      &lt;groupId>cn.hutool&lt;\/groupId><br>      &lt;artifactId>hutool-jwt&lt;\/artifactId><br>      &lt;version>5.8.22&lt;\/version><br>   &lt;\/dependency><br><br>   <em>&lt;!&#8211; GSon, Json &#8211;><br>   <\/em>&lt;dependency><br>      &lt;groupId>com.google.code.gson&lt;\/groupId><br>      &lt;artifactId>gson&lt;\/artifactId><br>      &lt;version>2.10.1&lt;\/version><br>   &lt;\/dependency><br><br>&lt;\/dependencies><br><br><br><strong>\u4e0b\u9762\u662f\u914d\u7f6e\u6587\u4ef6application.yml\uff1a<\/strong><br><br>server:<br>  address: 0.0.0.0<br>  port: 80<br><br>logging:<br>  level:<br>    org.springframework.security.web.FilterChainProxy: trace<br>    org.springframework.security.web.access.ExceptionTranslationFilter: trace<br>    org.springframework.security: debug<br><br>spring:<br>  application:<br>    name: test_SpringSecurity<br>  profiles:<br>    active: dev<br>  main.banner-mode: &#8216;off&#8217;<br>  datasource:<br>    driver-class-name: com.mysql.cj.jdbc.Driver<br>    username: db<br>    password: db_password<br>    url: jdbc:mysql:\/\/127.0.0.1:3306\/test?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia\/Shanghai<br>  jpa:<br>    database: MYSQL<br>    show-sql: true<br>    generate-ddl: true<br>    database-platform: org.hibernate.dialect.MySQLDialect<br>    hibernate:<br>      ddl-auto: update<br>      naming:<br>          implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy<br>          physical-strategy: org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy  # Springboot 3.x\u7528<br>#          physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy   # Springboot 2.x\u7528<br>    properties:<br>      hibernate:<br>        format_sql: true<br>        use_sql_comments: true<br><br><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u8981\u5efa\u7acb\u4e00\u4e2a\u914d\u7f6e\u7c7b\uff1a<\/strong><\/h2>\n\n\n\n<p>@Configuration<br>@EnableWebSecurity<br>\/\/@EnableMethodSecurity<br>@EnableGlobalMethodSecurity(prePostEnabled = true) \/\/controller\u542f\u7528\u6ce8\u89e3\u673a\u5236\u7684\u5b89\u5168,PreAuthorize\u624d\u4f1a\u6709\u6548<br>public class WebSecurityConfig {<br>    private static final Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class);<br>    @Autowired<br>    private MyAccessDeniedHandler accessDeniedHandler;<br>    @Autowired<br>    private MyUnauthorizedHandler unauthorizedHandler;<br><br>    @Bean <br>    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {<br>        return authConfig.getAuthenticationManager();<br>    }<br><br>    @Bean<br>    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {<br>        return new JwtAuthenticationTokenFilter();<br>    }<br>    @Bean<br>    public JwtAuthenticationProvider jwtAuthenticationProvider(){<br>        return new JwtAuthenticationProvider();<br>    }<br><br>    @Bean<br>    public PasswordEncoder passwordEncoder() {<br>        return new BCryptPasswordEncoder();<br>    }<br><br>    @Bean<br>    public WebSecurityCustomizer ignoringCustomizer() {<br>        \/\/\u4e0d\u9700\u8981\u9274\u6743\u7684\u8bbf\u95ee\u653e\u8fd9\u91cc\uff0c\u5728filter\u4e4b\u524d\u6267\u884c\uff1a<br>        return (web) -> web.ignoring()<br>                        \/\/\u5982\u679c\u8fd9\u4e9b\u8def\u5f84\u6ca1\u6709\u5728Controller\u4e2d\u914d\u7f6e\uff0c\u7528\u8fd9\u4e9b\u8def\u5f84\u6765\u8bbf\u95ee\u7684\u8bdd\u4e5f\u4f1a\u9274\u6743\u5931\u8d25\uff0c\u800c\u4e14\u8981\u8ddfController\u4e2d\u4e25\u683c\u5339\u914d\uff0c\u5305\u62ec\u8bbf\u95ee\u65f6\u5c3e\u90e8\u4e0d\u8981&#8221;\/&#8221;\u3002<br>                        \/\/\u5141\u8bb8\u5bf9\u4e8e\u7f51\u7ad9\u9759\u6001\u8d44\u6e90\u7684\u65e0\u6388\u6743\u8bbf\u95ee<br>                        .requestMatchers(HttpMethod.GET,&#8221;\/&#8221;,&#8221;\/*.html&#8221;,&#8221;\/*.css&#8221;,&#8221;\/*.js&#8221;,&#8221;\/static\/**&#8221;)<br>                        \/\/\u5bf9\u767b\u5f55\u6ce8\u518c\u5141\u8bb8\u533f\u540d\u8bbf\u95ee<br>                        .requestMatchers(&#8220;\/user\/login&#8221;,&#8221;\/user\/register&#8221;,&#8221;\/user\/logout&#8221;)<br>                        \/\/\u8de8\u57df\u8bf7\u6c42\u4f1a\u5148\u8fdb\u884c\u4e00\u6b21options\u8bf7\u6c42<br>                        .requestMatchers(HttpMethod.OPTIONS)<br>                        \/\/\u6d4b\u8bd5\u65f6\u5168\u90e8\u8fd0\u884c\u8bbf\u95ee.permitAll();<br>                        .requestMatchers(&#8220;\/test\/**&#8221;);<br>    }<br><br>    @Bean<br>    public SecurityFilterChain filterChain2(HttpSecurity httpSecurity) throws Exception {<br>        httpSecurity<br>                \/\/\u7531\u4e8e\u4f7f\u7528\u7684\u662fJWT\uff0c\u8fd9\u91cc\u4e0d\u9700\u8981csrf\u9632\u62a4<br>                .csrf((csrf)->csrf.disable())<br>                \/\/\u5df2\u7ecf\u7ecf\u8fc7\u9274\u6743filter\u7684\u8bbf\u95ee\uff0c\u518d\u8d70http\u8fc7\u6ee4\uff1a<br>                .authorizeHttpRequests((authorize) -> authorize<br>                        .anyRequest().authenticated());<br>        \/\/\u57fa\u4e8etoken\uff0c\u6240\u4ee5\u4e0d\u9700\u8981session<br>        httpSecurity.sessionManagement((sm)-> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS));<br>        \/\/ \u7981\u7528\u7f13\u5b58<br>        httpSecurity.headers((header)->header.cacheControl((control)->control.disable()));<br>        \/\/\u4f7f\u7528\u81ea\u5b9a\u4e49provider<br>        httpSecurity.authenticationProvider(jwtAuthenticationProvider());<br>        \/\/\u6dfb\u52a0JWT filter<br>        httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);<br>        \/\/\u6dfb\u52a0\u81ea\u5b9a\u4e49\u672a\u6388\u6743\u548c\u672a\u767b\u5f55\u7ed3\u679c\u8fd4\u56de<br>        httpSecurity.exceptionHandling((handle)->handle<br>                .accessDeniedHandler(accessDeniedHandler)<br>                .authenticationEntryPoint(unauthorizedHandler));<br><br>        return httpSecurity.build();<br>    }<br>}<br><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u4e0b\u9762\u662fJwtAuthenticationProvider\u7c7b\uff1a<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>\/\/\u767b\u5f55\u7684\u65f6\u5019\u7528\u6765\u9274\u6743\n<\/em>public class JwtAuthenticationProvider implements AuthenticationProvider {\n    private static final Logger <em>logger <\/em>= LoggerFactory.<em>getLogger<\/em>(JwtAuthenticationProvider.class);\n\n    @Autowired\n    private PasswordEncoder passwordEncoder;\n    @Autowired\n    private UserDetailsService userDetailsService;\n\n    @Override\n    public Authentication authenticate(Authentication authentication) throws AuthenticationException {\n        String username = String.<em>valueOf<\/em>(authentication.getPrincipal());\n        String password = String.<em>valueOf<\/em>(authentication.getCredentials());\n\n        UserDetails userDetails = userDetailsService.loadUserByUsername(username);\n        if(passwordEncoder.matches(password,userDetails.getPassword())){\n            if(userDetails instanceof UserDetailsImpl) {\n                ((UserDetailsImpl)userDetails).setIsLogin(true);\n            }\n            return new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities());\n        }\n        throw new BadCredentialsException(\"Password is error!\");\n    }\n\n    @Override\n    public boolean supports(Class&lt;?> authentication) {\n<em>\/\/        return UsernamePasswordAuthenticationToken.class.equals(authentication);\n        <\/em>return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);\n    }\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u4e0b\u9762\u662fJwtAuthenticationTokenFilter\u7c7b\uff1a<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>\/\/\u4e0d\u80fd\u5b9a\u4e49\u4e3aComponent\u3001Service\u7b49\u3002\n\/\/\u6240\u6709\u8bbf\u95ee\u90fd\u4f1a\u6765\u8fc7\u6ee4\u3002\n<\/em>public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {\n    private static final Logger <em>logger <\/em>= LoggerFactory.<em>getLogger<\/em>(JwtAuthenticationTokenFilter.class);\n\n    private final static String <em>AUTH_HEADER <\/em>= \"Authorization\";\n    private final static String <em>AUTH_HEADER_TYPE <\/em>= \"Bearer\";\n\n    @Autowired\n    private UserDetailsService userDetailsService;\n    @Autowired\n    private JwtAuthenticationProvider jwtAuthenticationProvider;\n\n    @Override\n    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {\n        <em>\/\/ get token from header:  Authorization: Bearer &lt;token>\n        <\/em>String authHeader = request.getHeader(<em>AUTH_HEADER<\/em>);\n        if (Objects.<em>isNull<\/em>(authHeader) || !authHeader.startsWith(<em>AUTH_HEADER_TYPE<\/em>)){\n            <em>\/\/\u4e0d\u505a\u9274\u6743\u5904\u7406\uff0c\u6240\u4ee5\u4f1a\u76f4\u63a5\u8fd4\u56de\u9274\u6743\u5931\u8d25\n            <\/em>filterChain.doFilter(request,response);\n            return;\n        }\n\n        String authToken = authHeader.split(\" \")[1];\n        <em>logger<\/em>.debug(\"authToken:{}\" , authToken);\n        <em>\/\/verify token\uff0ctoken\u7684\u63d0\u4f9b\u5728AuthController\u7684\u767b\u5f55\u65f6\u7ed9\u7684\u3002\n        <\/em>if (!JWTUtil.<em>verify<\/em>(authToken, MyConstant.<em>JWT_SIGNER<\/em>)) {\n            <em>logger<\/em>.info(\"invalid JWT token.\");\n            <em>\/\/\u4e0d\u505a\u9274\u6743\u5904\u7406\uff0c\u6240\u4ee5\u4f1a\u76f4\u63a5\u8fd4\u56de\u9274\u6743\u5931\u8d25\n            <\/em>filterChain.doFilter(request,response);\n            return;\n        }\n\n        final String userName = (String) JWTUtil.<em>parseToken<\/em>(authToken).getPayload(\"username\");\n        UserDetails userDetails = userDetailsService.loadUserByUsername(userName);\n\n        if(request.getRequestURI().equals(\"\/user\/logout\")){ <em>\/\/\u9000\u51fa\u767b\u5f55\n            <\/em>if(userDetails instanceof UserDetailsImpl) {\n                ((UserDetailsImpl)userDetails).setIsLogin(false);\n            }\n            response.setCharacterEncoding(\"UTF-8\");\n            response.setContentType(\"application\/json;charset=UTF-8\");\n            Message message = new Message&lt;>(true, \"\u9000\u51fa\u767b\u5f55\u6210\u529f\");\n            Gson gson = new Gson();\n            response.getWriter().println(gson.toJson(message));\n            response.getWriter().flush();\n            response.getWriter().close();\n            return; <em>\/\/\u4e0d\u518d\u8fc7\u6ee4\u4e86\u3002\n        <\/em>}\n        if(userDetails instanceof UserDetailsImpl){\n            if(!((UserDetailsImpl)userDetails).getIsLogin()){ <em>\/\/\u6ca1\u6709\u767b\u5f55\uff0c\u5373\u4f7f\u5e26\u4e86AUTH\u5b57\u6bb5\u4e5f\u4e0d\u884c\n                \/\/\u4e0d\u505a\u9274\u6743\u5904\u7406\uff0c\u6240\u4ee5\u4f1a\u76f4\u63a5\u8fd4\u56de\u9274\u6743\u5931\u8d25\n                <\/em>filterChain.doFilter(request,response);\n                return;\n            }\n        }\n\n\n        <em>\/\/\u5e26\u4e86token\uff0c\u4e14\u5df2\u7ecf\u767b\u5f55\u7684\u5904\u7406\u3002\n        \/\/ \u6ce8\u610f\uff0c\u8fd9\u91cc\u4f7f\u7528\u7684\u662f3\u4e2a\u53c2\u6570\u7684\u6784\u9020\u65b9\u6cd5\uff0c\u6b64\u6784\u9020\u65b9\u6cd5\u5c06\u8ba4\u8bc1\u72b6\u6001\u8bbe\u7f6e\u4e3atrue\n        <\/em>UsernamePasswordAuthenticationToken authentication =\n                new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());\n        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));\n\n        <em>\/\/\u5c06\u8ba4\u8bc1\u8fc7\u4e86\u51ed\u8bc1\u4fdd\u5b58\u5230security\u7684\u4e0a\u4e0b\u6587\u4e2d\u4ee5\u4fbf\u4e8e\u5728\u7a0b\u5e8f\u4e2d\u4f7f\u7528\n        <\/em>SecurityContextHolder.<em>getContext<\/em>().setAuthentication(authentication);\n\n        filterChain.doFilter(request, response);\n    }\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u4e0b\u9762\u662fMyAccessDeniedHandler\u7c7b\uff1a<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">@Component\npublic class MyAccessDeniedHandler implements AccessDeniedHandler {\n    private static final Logger <em>logger <\/em>= LoggerFactory.<em>getLogger<\/em>(MyAccessDeniedHandler.class);\n\n    @Override\n    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {\n        <em>\/\/logger.error(\"access error: \"+accessDeniedException.getMessage(), accessDeniedException);\n        logger<\/em>.error(\"access error: \"+accessDeniedException.getMessage());\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setContentType(\"application\/json;charset=UTF-8\");\n        Message message = new Message&lt;>(false, \"\u7981\u6b62\u8bbf\u95ee\");\n        Gson gson = new Gson();\n        response.getWriter().println(gson.toJson(message));\n        response.getWriter().flush();\n        response.getWriter().close();\n    }\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u4e0b\u9762\u662fMyUnauthorizedHandler\u7c7b\uff1a<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">@Component<br>public class MyUnauthorizedHandler implements AuthenticationEntryPoint {<br>    private static final Logger <em>logger <\/em>= LoggerFactory.<em>getLogger<\/em>(MyUnauthorizedHandler.class);<br>    @Override<br>    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {<br>        <em>\/\/logger.error(\"Unauthorized error: \"+authException.getMessage(), authException);<br><\/em><em>        <\/em><em>logger<\/em>.error(\"Unauthorized error: \"+authException.getMessage());<br>        response.setCharacterEncoding(\"UTF-8\");<br>        response.setContentType(\"application\/json;charset=UTF-8\");<br>        Message message = new Message&lt;&gt;(false, \"\u8ba4\u8bc1\u5931\u8d25\");<br>        Gson gson = new Gson();<br>        response.getWriter().println(gson.toJson(message));<br>        response.getWriter().flush();<br>        response.getWriter().close();<br>    }<br>}<\/pre>\n\n\n\n<p><strong>\u4e0b\u9762\u662fMyConstant\u7c7b\uff1a<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public class MyConstant {\n    private static final String <em>JWT_SIGN_KEY <\/em>= \"yunbu_key_de$xxSia4R2#@dffDE\";\n<em>    <\/em>public static final HMacJWTSigner <em>JWT_SIGNER <\/em>= new HMacJWTSigner(\n            AlgorithmUtil.<em>getAlgorithm<\/em>(\"HMD5\"), <em>JWT_SIGN_KEY<\/em>.getBytes(StandardCharsets.<em>UTF_8<\/em>));\n}<\/pre>\n\n\n\n<p><strong>\u672c\u5730\u8c03\u8bd5\u9700\u8981\uff0c\u589e\u52a0\u4e00\u4e2aCORS_Filter\u7c7b\u6765\u5141\u8bb8\u8de8\u57df\u8bf7\u6c42\uff1a<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">@Component\npublic class CORS_Filter implements Filter {\n    @Override\n    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {\n        HttpServletRequest reqs = (HttpServletRequest) req;\n        String curOrigin = reqs.getHeader(\"Origin\");\n        HttpServletResponse response = (HttpServletResponse) res;\n        response.setHeader(\"Access-Control-Allow-Origin\", curOrigin == null ? \"true\" : curOrigin);\n        response.setHeader(\"Access-Control-Allow-Credentials\", \"true\");\n        response.setHeader(\"Access-Control-Allow-Methods\", \"POST, PUT, PATCH, GET, OPTIONS, DELETE, HEAD\");\n        response.setHeader(\"Access-Control-Max-Age\", \"3600\");\n        response.setHeader(\"Access-Control-Allow-Headers\", \"Origin, X-Api-Key, Aaccess-Control-Allow-Origin, Authority, Authorization, Content-Type, Accept, Version-Info, X-Requested-With\");\n<em>\/\/        response.setContentType(\"application\/json;charset=UTF-8\");\n        <\/em>chain.doFilter(req, res);\n\n    }\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u4e0b\u9762\u4e3aRole\u548cUser\u76f8\u5173\u7684\u51e0\u4e2a\u7c7b\uff1a<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">@Data<br>@AllArgsConstructor<br>@NoArgsConstructor<br>public class Role {<br>    private RoleType roleType;<br>}<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">public enum RoleType {\n    <em>ADMIN<\/em>(\"admin\"),\n    <em>USER<\/em>(\"user\");\n\n    private String roleName;\n\n    RoleType(String roleName) {\n        this.roleName = roleName;\n    }\n\n    public String getRoleName() {\n        return roleName;\n    }\n}\n<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">@Data<br>@AllArgsConstructor<br>@NoArgsConstructor<br>public class User {<br>    private String userName;<br>    private String password;<br><br>    private static Boolean <em>isLogin <\/em>= false;  <em>\/\/static<\/em><em>\u662f\u4e34\u65f6\u6d4b\u8bd5\u4e3a\u4e86\u4fdd\u6301\u767b\u5f55\u72b6\u6001\uff0c\u540e\u7eed\u632a\u5230\u6570\u636e\u5e93\u540e\u5c31\u4e0d\u80fd\u7528<\/em><em>static<\/em><em>\u4e86\u3002<br><\/em><em>    <\/em>public static void setIsLogin(Boolean isLogin){<br>        User.<em>isLogin <\/em>= isLogin;<br>    }<br>    public static Boolean getIsLogin(){<br>        return User.<em>isLogin<\/em>;<br>    }<br><br>    private List&lt;Role&gt; roles;<br>}<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">@RequiredArgsConstructor<br>public class UserDetailsImpl implements UserDetails {<br>    private final User user;<br><br>    public void setIsLogin(Boolean isLogin){<br>        User.<em>setIsLogin<\/em>(isLogin);<br>    }<br>    public Boolean getIsLogin(){<br>        return User.<em>getIsLogin<\/em>();<br>    }<br><br>    @Override<br>    public Collection&lt;? extends GrantedAuthority&gt; getAuthorities() {<br>        return user.getRoles()<br>                .stream()<br>                .map(role -&gt; new SimpleGrantedAuthority(role.getRoleType().getRoleName()))<br>                .collect(Collectors.<em>toList<\/em>());<br>    }<br><br>    @Override<br>    public String getPassword() {<br>        return user.getPassword();<br>    }<br><br>    @Override<br>    public String getUsername() {<br>        return user.getUserName();<br>    }<br><br>    @Override<br>    public boolean isAccountNonExpired() {<br>        return true;<br>    }<br><br>    @Override<br>    public boolean isAccountNonLocked() {<br>        return true;<br>    }<br><br>    @Override<br>    public boolean isCredentialsNonExpired() {<br>        return true;<br>    }<br><br>    @Override<br>    public boolean isEnabled() {<br>        return true;<br>    }<br>}<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">@Service\npublic class UserDetailsServiceImpl implements UserDetailsService {\n    @Autowired\n    private PasswordEncoder passwordEncoder;\n\n    @Override\n    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {\n        User user = getUserByName(username);\n        if(user == null){\n            throw new UsernameNotFoundException(\"User isn't exist!\");\n        }\n        return new UserDetailsImpl(user);\n    }\n\n    public User getUserByName(String userName) {\n        if (!\"007\".equals(userName)) {\n            return null; <em>\/\/\u627e\u4e0d\u5230user\n        <\/em>}\n\n<em>\/\/        List&lt;Role> roles = List.of(new Role(RoleType.ADMIN), new Role(RoleType.USER));\n\/\/        List&lt;Role> roles = List.of( new Role(RoleType.USER));\n        <\/em>List&lt;Role> roles = List.<em>of<\/em>( new Role(RoleType.<em>ADMIN<\/em>));\n        return new User(userName, passwordEncoder.encode(\"123456\"), roles);\n    }\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">\u51e0\u4e2a\u548c\u524d\u7aef\u6253\u4ea4\u9053\u7684DTO\u7c7b\uff1a<\/h2>\n\n\n\n<p>@Data<br>public class Message&lt;T> {<br>    private Boolean success;<br>    private String msg;<br>    private Page page = null;<br>    private List&lt;T> dataList = null;<br><br>    public Message(){<br>        ;<br>    }<br><br>    public Message(Boolean success, String msg){<br>        setSuccessAndMsg(success, msg);<br>    }<br>    public void setSuccessAndMsg(Boolean success, String msg){<br>        this.success = success;<br>        this.msg = msg;<br>    }<br><br>    @Data<br>    @AllArgsConstructor<br>    @NoArgsConstructor<br>    public static class Page{<br>        private Integer num;<br>        private Integer size;<br>        private Integer total;<br>        private Long totalRec;<br>    }<br>}<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">@Data<br>public class SignInReq {<br>    private String username;<br>    private String password;<br>}<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">@Data\n@AllArgsConstructor\npublic class JWTAuthToken {\n    String jwtToken;\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u6700\u540e\u4e24\u4e2acontroller\u7c7b\uff0c\u7b2c\u4e00\u4e2a\u5904\u7406\u767b\u9646\u6ce8\u518c\uff1a<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">@RestController\n@RequestMapping(\"\/user\")\npublic class AuthController {\n    private static final Logger <em>logger <\/em>= LoggerFactory.<em>getLogger<\/em>(AuthController.class);\n\n    @Autowired\n    private AuthenticationManager authenticationManager;\n\n<em>    <\/em>@PostMapping (\"\/login\")\n    public Message&lt;JWTAuthToken> postLogin(@RequestBody SignInReq req) {\n        <em>logger<\/em>.info(\"postLogin, req: {}\", req);\n        UsernamePasswordAuthenticationToken authenticationToken =\n                new UsernamePasswordAuthenticationToken(req.getUsername(), req.getPassword());\n        authenticationManager.authenticate(authenticationToken); <em>\/\/<\/em><em>\u5728<\/em><em>config<\/em><em>\u91cc\u8bbe\u7f6e\u4e86\u4e4b\u540e\uff0c\u8fd9\u91cc\u4f1a\u8c03\u7528<\/em><em>JwtAuthenticationProvider<\/em><em>\u7684\u9274\u6743\n<\/em><em>\n<\/em><em>        <\/em><em>\/\/<\/em><em>\u4e0a\u4e00\u6b65\u6ca1\u6709\u629b\u51fa\u5f02\u5e38\u8bf4\u660e\u767b\u5f55\u6210\u529f\uff0c\u6211\u4eec\u5411\u7528\u6237\u9881\u53d1<\/em><em>jwt<\/em><em>\u4ee4\u724c\uff0c\u68c0\u9a8c\u5728<\/em><em>JwtAuthenticationTokenFilter<\/em><em>\u91cc\u9762\u3002\n<\/em><em>        <\/em>String token = JWT.<em>create<\/em>()\n                .setPayload(\"username\", req.getUsername())\n                .setSigner(MyConstant.<em>JWT_SIGNER<\/em>)\n                .sign();\n\n        <em>\/\/<\/em><em>\u767b\u5f55\u6210\u529f\uff0c\u8fd4\u56de<\/em><em>JWT<\/em><em>\u683c\u5f0f\u7684<\/em><em>token<\/em><em>\u7ed9\u5ba2\u6237\u7aef\u540e\u7eed\u518d\u8bf7\u6c42\u65f6\u4ece<\/em><em>Header<\/em><em>\u7684\n<\/em><em>        <\/em>JWTAuthToken jwtAuthToken = new JWTAuthToken(token);\n        Message&lt;JWTAuthToken> message = new Message&lt;>(true, \"\");\n        message.setDataList(new ArrayList&lt;JWTAuthToken>(Arrays.<em>asList<\/em>(jwtAuthToken)));\n        return message;\n    }\n\n    @GetMapping (\"\/login\")\n    public String getLogin() {\n        <em>logger<\/em>.info(\"getLogin\");\n        return \"getLogin\";\n    }\n\n    @PostMapping (\"\/register\")\n    public Message&lt;String> postRegister(@RequestBody SignInReq req) {\n        <em>logger<\/em>.info(\"postRegister, req: {}\", req);\n        <em>\/\/<\/em><em>\u5b58\u5165\u6570\u636e\u5e93\u3002\n<\/em><em>        <\/em>Message&lt;String> message = new Message&lt;>(true, \"\");\n        message.setDataList(new ArrayList&lt;String>(Arrays.<em>asList<\/em>(\"\u6ce8\u518c\u6210\u529f\")));\n        return message;\n    }\n}<\/pre>\n\n\n\n<p><strong>\u7b2c\u4e8c\u4e2a\u7528\u6765\u5904\u7406\u4e1a\u52a1\uff1a<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">@RestController\n@RequestMapping(\"\/aaa\")\npublic class TestController {\n    private static final Logger <em>logger <\/em>= LoggerFactory.<em>getLogger<\/em>(TestController.class);\n\n    @RequestMapping(\"\/aaa\")\n    public Message&lt;String> aaa() {\n        <em>logger<\/em>.info(\"aaa\");\n        Message&lt;String> message = new Message&lt;>(true, \"\");\n        message.setDataList(new ArrayList&lt;String>(Arrays.<em>asList<\/em>(\"aaa\")));\n        return message;\n    }\n\n    @PreAuthorize(\"hasAuthority('admin')\") <em>\/\/\u9700\u8981\u4ee5\u4ec0\u4e48\u89d2\u8272\u6765\u8bbf\u95ee\n    <\/em>@GetMapping(\"\/bbb\")\n    public Message&lt;String> bbb(){\n        Message&lt;String> message = new Message&lt;>(true, \"\");\n        message.setDataList(new ArrayList&lt;String>(Arrays.<em>asList<\/em>(\"bbb\")));\n        return message;\n    }\n\n    @PreAuthorize(\"hasAuthority('user')\")\n    @GetMapping(\"\/ccc\")\n    public Message&lt;String> ccc(){\n        Message&lt;String> message = new Message&lt;>(true, \"\");\n        message.setDataList(new ArrayList&lt;String>(Arrays.<em>asList<\/em>(\"ccc\")));\n        return message;\n    }\n\n    @PreAuthorize(\"hasAuthority('user') || hasAuthority('admin')\")\n    @GetMapping(\"\/ddd\")\n    public Message&lt;String> ddd(){\n        Message&lt;String> message = new Message&lt;>(true, \"\");\n        message.setDataList(new ArrayList&lt;String>(Arrays.<em>asList<\/em>(\"ddd\")));\n        return message;\n    }\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u6211\u4eec\u4f7f\u7528curl\u6765\u6a21\u62df\u6ce8\u518c\u3001\u767b\u9646\u3001\u8bbf\u95ee\u3001\u9000\u51fa\u767b\u5f55\u7b49\u64cd\u4f5c\uff1a<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\"><em>\/\/<strong>\u6ce8\u518c<\/strong>(\u5b58\u6570\u636e\u5e93\u65f6\u624d\u6709\u7528\uff0c\u73b0\u5728\u4e34\u65f6\u6d4b\u8bd5\u56fa\u5b9a\u4e86\u7528\u6237\u6ca1\u610f\u4e49)\uff1a curl -X POST -H 'Content-Type:application\/json' -d '{\"username\":\"007\",\"password\":\"123456\"}'  'http:\/\/127.0.0.1\/user\/register'<\/em>\n<em>\n\/\/<strong>\u6a21\u62df\u767b\u5f55<\/strong>\uff1a curl -X POST -H 'Content-Type:application\/json' -d '{\"username\":\"007\",\"password\":\"123456\"}'  'http:\/\/127.0.0.1\/user\/login'\n\/\/\u4f1a\u6253\u5370\u51fa\u8fd4\u56de\u7684 token\uff0c\u8bb0\u4f4f\u8be5token\u3002<\/em>\n<em>\n\/\/<strong>\u6a21\u62df\u767b\u5f55\u540e\u7684\u8bbf\u95ee<\/strong>\uff1acurl -X GET -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJITUQ1In0.eyJ1c2VybmFtZSI6IjAwNyJ9.nj2Wp_-CCQGZ44-8uomApw' 'http:\/\/127.0.0.1\/aaa\/aaa'\n\/\/\u8fd9\u91cc\u8def\u5f84\/aaa\/aaa\u3001\/aaa\/bbb\u3001\/aaa\/ccc\u3001\/aaa\/ddd\u7684\u5904\u7406\u53c2\u8003\uff1aTestController<\/em>\n<em>\n\/\/<strong>\u6a21\u62df\u9000\u51fa\u767b\u5f55<\/strong>\uff1a curl -X GET  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJITUQ1In0.eyJ1c2VybmFtZSI6IjAwNyJ9.nj2Wp_-CCQGZ44-8uomApw' 'http:\/\/127.0.0.1\/user\/logout'<\/em><\/pre>\n\n\n\n<p><br><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5148\u5f15\u5165pom.xml\uff0c\u4e3b\u8981\u770bdependency\u90e8\u5206\uff1a &lt;parent> &lt;groupId>org &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[63,13],"tags":[889,888,887,890,75,174,74],"class_list":["post-1153","post","type-post","status-publish","format-standard","hentry","category-63","category-13","tag-jwt","tag-security","tag-spring","tag-web-token","tag-75","tag-174","tag-74"],"views":965,"_links":{"self":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1153","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1153"}],"version-history":[{"count":1,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1153\/revisions"}],"predecessor-version":[{"id":1154,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1153\/revisions\/1154"}],"wp:attachment":[{"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1153"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1153"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.max-shu.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}