spring boot 整合 spring security4

我們?cè)诰帉慦eb應(yīng)用時(shí),經(jīng)常需要對(duì)頁(yè)面做一些安全控制,比如:對(duì)于沒(méi)有訪問(wèn)權(quán)限的用戶需要轉(zhuǎn)到登錄表單頁(yè)面。要實(shí)現(xiàn)訪問(wèn)控制的方法多種多樣,可以通過(guò)Aop、攔截器實(shí)現(xiàn),也可以通過(guò)框架實(shí)現(xiàn)(如:Apache Shiro、Spring Security)。

本文將具體介紹在Spring Boot中如何使用Spring Security進(jìn)行安全控制。
整體框架: spring boot spring data jpa spring security

心得

在整理當(dāng)前框架時(shí),遇到了幾個(gè)問(wèn)題

<sec:authorize access="hasRole('ROLE_USER')">
     這里是角色ROLE_USER可以看到
</sec:authorize> 
<sec:authorize url="/admin">
   這里是具有 /admin 資源的用戶可以看到
</sec:authorize>

當(dāng)時(shí)官網(wǎng)是這樣描述著兩個(gè)標(biāo)簽的
此標(biāo)記用于確定是否應(yīng)評(píng)估其內(nèi)容。在spring 3.0,它可以以兩種方式使用 。第一種方法使用了網(wǎng)絡(luò)的安全性表達(dá),在指定access標(biāo)簽的屬性。表達(dá)式求值將被委托給SecurityExpressionHandler<FilterInvocation>應(yīng)用程序上下文中定義(你應(yīng)該在你的基于Web的表達(dá)<http>空間配置,以確保該服務(wù)可用)。所以,例如,你可能有<sec:authorize access="hasRole('ROLE_USER')"></sec:authorize>這這種標(biāo)簽可以直接使用 .
但是對(duì)于 URL 來(lái)講就沒(méi)那么簡(jiǎn)單了.需要自定義DefaultWebInvocationPrivilegeEvaluator類. 下面我會(huì)給出詳細(xì)設(shè)計(jì)代碼,在這之前我想多說(shuō)一句,當(dāng)時(shí)擴(kuò)展的時(shí)候我遇到了標(biāo)簽不起作用,百度 谷歌了好久,也沒(méi)有解決問(wèn)題.我在群里問(wèn)人的時(shí)候,群里的回答也是讓我大寫的服...一個(gè)個(gè)的都不認(rèn)字嗎?
有人回答說(shuō)用 shiro 吧....有人回答說(shuō),誰(shuí)還用 JSP... 有人回答說(shuō),自定義標(biāo)簽吧...有人回答說(shuō),用 hasrole 標(biāo)簽吧... url 沒(méi)用....我真是服了,,我求求你們,你們是怎么當(dāng)上程序員的啊!!!!!當(dāng)別人問(wèn)你們問(wèn)題的時(shí)候,,你們的回答也是大寫的服!!!!!! 別人用 jsp 咋了,,跟當(dāng)前問(wèn)的問(wèn)題有任何關(guān)系嗎?所以啊有什么問(wèn)題還是靠自己解決啊.. 于是就跟蹤源代碼DefaultWebInvocationPrivilegeEvaluator. java中有個(gè)securityInterceptor屬性.這個(gè)屬性就決定是用擴(kuò)展自定義的類還是用 springsecurity 本身自己的類...最后發(fā)現(xiàn)是我這個(gè)地方?jīng)]有注入進(jìn)去..查詢了官方 API, 原來(lái)發(fā)現(xiàn) javaconfig 的方式在在

 public void configure(WebSecurity web) throws Exception {
       web.securityInterceptor(myFilterSecurityInterceptor);
       web.privilegeEvaluator(customWebInvocationPrivilegeEvaluator());
}

這樣才能做到注入自己的擴(kuò)展的FilterSecurityInterceptor,下面我會(huì)給出詳細(xì)代碼.
參考文檔 http://docs.spring.io/spring-security/site/docs/4.2.2.BUILD-SNAPSHOT/reference/htmlsingle/
http://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/config/annotation/web/builders/WebSecurity.html
解決問(wèn)題還是得靠自己. 多看文檔,多跟蹤源代碼,多看 API. 下面開(kāi)始進(jìn)入正題.

表設(shè)計(jì)

springsecurity框架的表設(shè)計(jì)還是很簡(jiǎn)單的, user 用戶表, role 角色表, resource 資源表.然后三者通過(guò)關(guān)系關(guān)聯(lián),我這里設(shè)計(jì)了5張表, user,role,resource,user_role,role_resource 其中user_role表是用戶與角色之間的關(guān)系,多對(duì)多,role_resource 關(guān)系也是這樣.

實(shí)體類

user.java
@Entity
@Table(name = "ad_operator_info")
public class User extends BaseEntity {
   /**
    * 主鍵
    */
   @Id
   @GeneratedValue(generator = "uuid")
   @GenericGenerator(name = "uuid", strategy = "uuid")
   @Column(name = "oper_id", length = 32)
   private String operId;
   /**
    * 用戶名
    */
   @Column(name = "user_name")
   private String userName;
   /**
    * 密碼
    */
   private String password;

   @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
   @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
   private Set<Role> roles;

   //省略 get... set..
}
role.java
@Entity
@Table(name = "ad_role")
public class Role extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
    private Set<OperatorInfo> users;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinTable(name = "ad_roles_resources", joinColumns = {@JoinColumn(name = "rid")}, inverseJoinColumns = {@JoinColumn(name = "eid")})
    private Set<Resource> resources;
   // 省略 get set
}
Resource.java
@Entity
@Table(name = "ad_web_resource")
public class WebResource extends BaseEntity {

    private static final long serialVersionUID = 7926081201477024763L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id; // 主鍵

    private String name; // 資源名稱

    private String url;

    @Column(name="remark",length=200)
    private String remark;//備注

    @Column(name="methodName",length=400)
    private String methodName;//資源所對(duì)應(yīng)的方法名

    @Column(name="methodPath",length=1000)
    private String methodPath;//資源所對(duì)應(yīng)的包路徑

    private String sn;

    private String value; // 資源標(biāo)識(shí)
   
   // 省略 get set  這里的屬性可以根據(jù)自己的業(yè)務(wù)來(lái).
}

實(shí)體類就此準(zhǔn)備完畢. 下面加入 springsecurity 的 jar 包

  1. 下載 jar
<parent>  
        <groupId>org.springframework.boot</groupId>  
        <artifactId>spring-boot-starter-parent</artifactId>  
        <version>1.4.1.RELEASE</version>  
    </parent>  
    <dependencies>  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-web</artifactId>  
        </dependency>  
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-security</artifactId>  
        </dependency>  
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>4.2.1.RELEASE</version>
        </dependency>
</dependencies>  

2 .Spring Security配置
創(chuàng)建Spring Security的配置類 WebSecurityConfig,也是注入自己定義擴(kuò)展FilterSecurityInterceptor的重要類 ,具體如下:

import com.pwkj.potevio.adp.auth.MyFilterSecurityInterceptor;
import com.pwkj.potevio.adp.auth.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
/**
 * Created by PrimaryKey on 17/2/4.
 *
 * @EnableWebSecurity: 禁用Boot的默認(rèn)Security配置,配合@Configuration啟用自定義配置(需要擴(kuò)展WebSecurityConfigurerAdapter)
 * @EnableGlobalMethodSecurity(prePostEnabled = true): 啟用Security注解,例如最常用的@PreAuthorize
 * configure(HttpSecurity): Request層面的配置,對(duì)應(yīng)XML Configuration中的<http>元素
 * configure(WebSecurity): Web層面的配置,一般用來(lái)配置無(wú)需安全檢查的路徑
 * configure(AuthenticationManagerBuilder): 身份驗(yàn)證配置,用于注入自定義身份驗(yàn)證Bean和密碼校驗(yàn)規(guī)則
 */


@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailService myUserDetailService;
    @Autowired
    private MyFilterSecurityInterceptor myFilterSecurityInterceptor;

   @Bean
    @Primary
    public DefaultWebInvocationPrivilegeEvaluator customWebInvocationPrivilegeEvaluator() {
        return new DefaultWebInvocationPrivilegeEvaluator(myFilterSecurityInterceptor);
    }
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // javaconfig 配置是這樣 set 進(jìn)去的.
        web.securityInterceptor(myFilterSecurityInterceptor);
        web.privilegeEvaluator(customWebInvocationPrivilegeEvaluator());
        web.
                ignoring()
                .antMatchers("/assets/**", "/login", "/login/success", "/kaptcha/**", "/**/*.jsp");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/resources", "/login", "/kaptcha/**").permitAll()//訪問(wèn):這些路徑 無(wú)需登錄認(rèn)證權(quán)限
                .anyRequest().authenticated() //其他所有資源都需要認(rèn)證,登陸后訪問(wèn)
                //.antMatchers("/resources").hasAuthority("ADMIN") //登陸后之后擁有“ADMIN”權(quán)限才可以訪問(wèn)/hello方法,否則系統(tǒng)會(huì)出現(xiàn)“403”權(quán)限不足的提示
         .and()
                .formLogin()
                .loginPage("/")//指定登錄頁(yè)是”/”
                .permitAll()
                .successHandler(loginSuccessHandler()) //登錄成功后可使用loginSuccessHandler()存儲(chǔ)用戶信息,可選。
         .and()
                .logout()
                .logoutUrl("/admin/logout")
                .logoutSuccessUrl("/") //退出登錄后的默認(rèn)網(wǎng)址是”/home”
                .permitAll()
                .invalidateHttpSession(true);
               // .and()
                //.rememberMe()//登錄后記住用戶,下次自動(dòng)登錄,數(shù)據(jù)庫(kù)中必須存在名為persistent_logins的表
                //.tokenValiditySeconds(1209600);
        http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);

    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        //指定密碼加密所使用的加密器為passwordEncoder()
        //需要將密碼加密后寫入數(shù)據(jù)庫(kù)
        auth.userDetailsService(myUserDetailService);//.passwordEncoder(bCryptPasswordEncoder());
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(4);
    }

    @Bean
    public LoginSuccessHandler loginSuccessHandler() {
        return new LoginSuccessHandler();
    }
}

編寫LoginSuccessHandler.java 此類是在登陸成功之后做一些業(yè)務(wù)操作

package com.pwkj.potevio.adp.config;

import com.pwkj.potevio.adp.entity.OperatorInfo;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;

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

/**
 * Created by PrimaryKey on 17/2/4.
 */
public class LoginSuccessHandler extends
        SavedRequestAwareAuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response, Authentication authentication) throws IOException,
            ServletException {
        //獲得授權(quán)后可得到用戶信息   可使用OperatorInfoService進(jìn)行數(shù)據(jù)庫(kù)操作
        OperatorInfo userDetails = (OperatorInfo) authentication.getPrincipal();
       /* Set<SysRole> roles = userDetails.getSysRoles();*/
        //輸出登錄提示信息
        System.out.println("管理員 " + userDetails.getName() + " 登錄");

        System.out.println("IP :" + getIpAddress(request));

        super.onAuthenticationSuccess(request, response, authentication);
    }


    public String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

下面是自定義的過(guò)濾器,也是最重要的集成代碼.
首先編寫 MyInvocationSecurityMetadataSource.java 此類是首先加載的,用于加載資源配置.用resourceMap對(duì)象存儲(chǔ)url --> value

package com.pwkj.potevio.adp.auth;

/**
 * Created by PrimaryKey on 17/2/4.
 */

import com.pwkj.potevio.adp.dao.WebResourceDao;
import com.pwkj.potevio.adp.entity.WebResource;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;

@Service
public class MyInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private static Map<String, Collection<ConfigAttribute>> resourceMap = null;
    private org.slf4j.Logger LOG = LoggerFactory.getLogger(getClass());

    @Autowired
    private WebResourceDao webResourceDao;

    /**
     * 加載資源,初始化資源變量
     */
    @PostConstruct
    public void loadResourceDefine() {
        if (resourceMap == null) {
            resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
            List<WebResource> resources = webResourceDao.findAll();
            for (WebResource resource : resources) {
                Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
                ConfigAttribute configAttribute = new SecurityConfig(resource.getValue());
                configAttributes.add(configAttribute);
                resourceMap.put(resource.getUrl(), configAttributes);
            }
        }
        LOG.info("security info load success!!");
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        if (resourceMap == null) loadResourceDefine();
        String requestUrl = ((FilterInvocation) object).getRequestUrl();
       // 返回當(dāng)前 url  所需要的權(quán)限
         return resourceMap.get(requestUrl);
    }



    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}

其次編寫 MyUserDetailService.java 此類用來(lái)獲取用戶的所有權(quán)限.

package com.pwkj.potevio.adp.auth;

import com.pwkj.potevio.adp.entity.OperatorInfo;
import com.pwkj.potevio.adp.entity.Role;
import com.pwkj.potevio.adp.entity.WebResource;
import com.pwkj.potevio.adp.service.OperatorInfoService;
import com.pwkj.potevio.adp.service.WebResourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.stereotype.Service;

import java.util.*;

/**
 * Created by PrimaryKey on 17/2/4.
 * 二
 */
@Service
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    private OperatorInfoService operatorInfoService;

    @Autowired
    private WebResourceService webResourceService;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        //取得用戶
        OperatorInfo operatorInfo = operatorInfoService.findByUserName(userName);
        if (operatorInfo == null) {
            throw new UsernameNotFoundException("UserName " + userName + " not found");
        }
        // 取得用戶的權(quán)限
        Collection<GrantedAuthority> grantedAuths = obtionGrantedAuthorities(operatorInfo);
        Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>();
        for (Role role : operatorInfo.getRoles()) {
            grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
        }
        // 封裝成spring security的user
        User userDetail = new User(operatorInfo.getUserName(), operatorInfo.getPassword(),
                true,//是否可用
                true,//是否過(guò)期
                true,//證書(shū)不過(guò)期為true
                true,//賬戶未鎖定為true ,
                grantedAuths);
        return userDetail;
    }

    // 取得用戶的權(quán)限
    private Set<GrantedAuthority> obtionGrantedAuthorities(OperatorInfo operatorInfo) {
        List<WebResource> resources = new ArrayList<WebResource>();
        //獲取用戶的角色
        Set<Role> roles = operatorInfo.getRoles();
        for (Role role : roles) {
            Set<WebResource> res = role.getResources();
            for (WebResource resource : res) {
                resources.add(resource);
            }
        }
        Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();
        for (WebResource r : resources) {
            //用戶可以訪問(wèn)的資源名稱(或者說(shuō)用戶所擁有的權(quán)限)
            authSet.add(new SimpleGrantedAuthority(r.getValue()));
        }
        return authSet;
    }
}
```
再次編寫 ```MyFilterSecurityInterceptor.java``` 用于跳轉(zhuǎn)
```
package com.pwkj.potevio.adp.auth;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;

import javax.servlet.*;
import java.io.IOException;

/**
 * Created by PrimaryKey on 17/2/4.
 *
 * 三
 */
@Service
public class MyFilterSecurityInterceptor extends FilterSecurityInterceptor implements Filter {

    @Autowired
    private FilterInvocationSecurityMetadataSource securityMetadataSource;

    @Autowired
    public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {
        super.setAccessDecisionManager(myAccessDecisionManager);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        FilterInvocation fi = new FilterInvocation(servletRequest, servletResponse, filterChain);
        invoke(fi);
    }

    public void invoke(FilterInvocation fi) throws IOException, ServletException {
        //fi里面有一個(gè)被攔截的url
        //里面調(diào)用MyInvocationSecurityMetadataSource的getAttributes(Object object)這個(gè)方法獲取fi對(duì)應(yīng)的所有權(quán)限
        //再調(diào)用MyAccessDecisionManager的decide方法來(lái)校驗(yàn)用戶的權(quán)限是否足夠
        InterceptorStatusToken token = super.beforeInvocation(fi);
        try {
            //執(zhí)行下一個(gè)攔截器
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } finally {
            super.afterInvocation(token, null);
        }
    }

    @Override
    public void destroy() {

    }

    @Override
    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;
    }

    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return this.securityMetadataSource;
    }
}

```
最后編寫```MyAccessDecisionManager.java``` 類用來(lái)判斷當(dāng)前用戶是否有訪問(wèn)權(quán)限.
```
package com.pwkj.potevio.adp.auth;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Iterator;

/**
 * Created by PrimaryKey on 17/2/4.
 *
 * 最后一個(gè)類
 */
@Service
public class MyAccessDecisionManager implements AccessDecisionManager {
    @Override
    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {


        // TODO  權(quán)限 .... >>>
        if (configAttributes == null) {
            return;
        }
        //所請(qǐng)求的資源擁有的權(quán)限(一個(gè)資源對(duì)多個(gè)權(quán)限)
        Iterator<ConfigAttribute> iterator = configAttributes.iterator();
        while (iterator.hasNext()) {
            ConfigAttribute configAttribute = iterator.next();
            //訪問(wèn)所請(qǐng)求資源所需要的權(quán)限
            String needPermission = configAttribute.getAttribute();
             //用戶所擁有的權(quán)限authentication
            for (GrantedAuthority ga : authentication.getAuthorities()) {
                System.out.println("-----------PrimaryKey-----------ga.getAuthority()值=" + ga.getAuthority() + "," + "當(dāng)前類=MyAccessDecisionManager.decide()");
                if (needPermission.equals(ga.getAuthority())) {
                    return;
                }
            }
        }
        throw new AccessDeniedException("沒(méi)有權(quán)限訪問(wèn)!");
    }

    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}

```
 

到此java 代碼就已經(jīng)完成編寫了. 然后抓緊時(shí)間寫個(gè)```LoginController``` 吧

```
    @PostMapping("/login")
    public String login(String userName, String password,Model model) {
        HttpSession session = request.getSession();
        User user = userService.findByUserName(userName);
        if (!passwordEncoder.matches(password, user.getPassword())) {
             model.addAttribute("error", "用戶名或密碼錯(cuò)誤");
            return "/pages/login";
        }
        // 這句代碼會(huì)自動(dòng)執(zhí)行咱們自定義的 ```MyUserDetailService.java``` 類
        Authentication authentication = myAuthenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName, password));
        if (!authentication.isAuthenticated()) {
            throw new BadCredentialsException("Unknown username or password");
        }
        SecurityContext securityContext = SecurityContextHolder.getContext();
        securityContext.setAuthentication(authentication);
        session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
        session.setAttribute(PlatformConstant.SESSION_OPERATOR, user);
         operateLogService.saveOperateLog(user, request.getRemoteAddr());
        return "index";
    }
```
頁(yè)面如下
```login.jsp```
```
<form action="/user/login"method="POST">
<table>
    <tr>
        <td>username:</td>
        <td><input type='text'name='username'></td>
    </tr>
    <tr>
        <td>password:</td>
        <td><input type='password'name='password'></td>
    </tr>
    <tr>
        <td><input name="reset"type="reset"></td>
        <td><input name="submit"type="submit"></td>
    </tr>
</table>
</form>
```
登陸之后跳轉(zhuǎn)到 index.jsp 
```
這是首頁(yè),歡迎<sec:authentication property="name"/>!<br>

<sec:authentication property="authorities"/>  <br/>

<a href="admin.jsp">進(jìn)入admin頁(yè)面</a>

<sec:authorize url='/other1.jsp' >
    <a href="other1.jsp">權(quán)限1</a>
</sec:authorize> 

<sec:authorize url='/other2.jsp' >
<a href="other2.jsp">權(quán)限2</a>
</sec:authorize>

<sec:authorize url='/other3.jsp' >
    <a href="other3.jsp">權(quán)限3</a>
</sec:authorize> 
```
到此,整個(gè)標(biāo)簽庫(kù)都會(huì)生效了,,,由于時(shí)間有限,,寫的有點(diǎn)倉(cāng)促了,哪里不懂的可以問(wèn)我.小伙伴抓緊時(shí)間試試吧...
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容